マン・うどん・インターフェース

https://sassembla.github.com/Public/

どんなことをしようとしているか、有料で手伝って欲しいか

→ドキュメントの翻訳



こんな会社があってね

KISSAKI Inc.



UnityのAssetを作って売ったりしている

こんなのとか。

AssetRails


SublimeSocketAsset



今回の対象:UnityのAssetStoreで出す、Automatine というAsset

TOC作る

井上。

全体量が見積もれるような感じで。


4月から

それまでにTOCとか送る。



月極めが楽(井上の都合。

月ごとの限界は、翻訳量とかと合わせて計算してもらってお任せ。

ひと月に大量に渡したとしても、お値段分まで。



データ形態

テキストでアップする → markdown化



やりとり

Slackかな。


wrote outsource マン・うどん・インターフェース wrote htmlResource
twitback with Twitter-account
wrote htmlResource

マン・うどん・インターフェース

https://sassembla.github.com/Public/
wrote htmlResource

Xcodeをアレするツールの選定


概要

Xcodeをいろんなバージョンinstallしたり切り替えたりするじゃん、

最新だとどんなのがデファクトなん?って思って色々見ていた。


xcode:installっていうツールがfastlaneに含まれてて、そいつがXcodeのinstallとかをやってくれるんだけど、

とにかくその部分のrubyランタイムのバージョンへの依存度合いがヤバくて、うわー捨ててーってなってきたので代替を探していたら、いいのがあった。



そんなxcodes

これ

https://github.com/RobotsAndPencils/xcodes


・swift製

・homebrew(これもまあrubyだが)経由でインストール可能


という感じで、まあ問題なく動くのでこれでいこうと思う。



使い方


xcodes list

で適当に対象の一覧が出せて、適当にverを選んで


xcodes install 11.3.1

とかで、最後にPCのパスワードを入力してインストールが完了する。


使う時は、

xcodes select 11.3.1


とかをやっておくと、xcodeproj開いた時とかに開かれるようになる。






wrote 2020/05/25 2:58:02

TextMesh Proのエッジケース現象まとめ


概要

さわれば触るほど楽しいケースが出てくる。UUebViewでもしこたま遭遇していたが、LayouTaroを作っているとさらに出会う。

次のようなファンキーを発見した。多分以前のメモとかには出てこない。


・TMProはwhitespaceが特定の位置に来るとファンキーなことをする

・TMProが改行する位置をミスる



TMProはwhitespaceが特定の位置に来るとファンキーなことをする

whitespace、つまりスペースを含んだテキストとかを食わせると、まあ、表示幅とテキストの長さによっては、スペースが行の末尾に来ることがあるだろう。

例えば次のようなテキストがあるとする。[あ]、[い] の間には5つのスペースが入っている。

あ     い


これを、例えば [あ] と [い] の間で改行が入るような幅に表示しようとするとしよう。

[あ]の後ろ、3つめのスペースを詰めたところでちょうど改行が起きるような幅を想定する。

あ   // 3つめのスペースで改行が発生するような幅

  い// 2つのスペースのあとに[い]が来る

こうなってくれるのがまあ、予想としては正しいと思うんだよね。



そしてここでもう一つ、理想としては、レイアウトする枠に対して、レイアウトされる文字は枠幅よりイコールかちょっと少ない位置で折り返しが発生する。

具体的には、1行目のコンテンツの返す幅は、


         ↓ この位置を表す幅 = あ + スペース + スペース + スペース の幅を合計した値で、これは枠幅より小さいはずだよな。

あ   // 3つめのスペースで改行が発生するような幅

  い// 2つのスペースのあとに[い]が来る

[あ]と[スペース]の幅をそれぞれ100pxだと仮定しよう。つまり1行目の幅は400あるはずなんだ。


でも違うんだ。実際はこうなるんだ。


あ   // 3つめのスペースで改行が発生するような幅

// 前の2つのスペースが消える

!?

やったぜ!!、[い]の前の2つのスペースが消えたね! なんで?



そして1行目の幅は? 幅はどうなんだ、教えてくれセフィロス。


 ↓ この位置を表す幅 = [あ] 単独の幅、、

あ   // 3つめのスペースで改行が発生するような幅

// 前の2つのスペースが消える



100を返してくる。 ふーん、 400じゃないんだ、、なんで、、?


カラクリはこうだ。

1. TMProは文章の末尾に来るスペースの存在自体をなかったことにするが、消す前にきちんと幅を測って改行だけはさせてくれる

2. TMProは文章の末尾に来るスペースを消すので、行に入るテキストの幅は、「スタート」から「最後に現れるスペース以外の文字」の幅になる



1.によって、2行目に来るはずの2つのスペースが消され、それでも改行だけはできて、

2.によって誤った幅情報が得られる。



これらを回避すると、スペースがロストインスペースしないで済み、正確な幅情報が得られる。



TMProが改行する位置をミスる

これには本当に参った。


レイアウトする枠の長さを1000pxとしよう。

カーニングの組み合わせ込みで幅100pxの文字なら、10個置くとちょうど枠を満たす。


          ↓ここがちょうど、枠のサイズと重なる

ああああああああああ


このパターンだと、例えば11文字目に何か文字がくれば、その文字は改行された先に送り出される。

11文字目に[い]が来るとしたら、


ああああああああああ


こうなると思うんだよね。

だがここで、[あ]が、もし、101pxの幅を持つとしたら?


誇張してちょっと大きなフォントでやったとしよう。同じフォントでも幅は変わる。


10個並べたら1010pxになるから、10個めの[あ]は2行目に行くはずだよね。


                                                           ↓枠幅がここ。 9個目の[あ]と枠幅の隙間に最後の[あ]は入らないよなあ。

ああああああああああ//x 明確に入らないよね。

あい


ところが。こうならない組み合わせがある。


レイアウトした文字が枠のサイズを超えるんだ。

具体的にいうと、次のようにレイアウトされる。


                                                           ↓枠幅がここ。 

ああああああああああ//枠幅をワイルドに超えてくるんだが?


枠のサイズを与えてさーレイアウトをお願いしてるのにさー、枠のサイズを超えてレイアウトされるんだよ。怖い。

これはTMPro内での計算が1pxくらいの誤差を含むから起きる現象で、事前の回避策はない。

ふとレイアウトしてみて、レイアウト結果が枠の幅を超えていることがあって、それで発覚した。

ひどい時は大変ブレイブな感じで枠外にレイアウトが飛び出す。1文字だけだけどさー、与えた枠は守って欲しいんだよなー。

ほとんど全てのケースで枠内に収まるが、TMPro内の計算結果というブラックボックス性のせいで、レイアウトするまで観測できない。


なので、レイアウト後に恐る恐る計測して、枠を超えていたら、なんとかしよう。


ところで

ここで紹介した2つの問題が合成して発生することがあって、

・TMProが改行位置をミスり

・なおかつ1行目の末尾がスペースだと、

なんと、飛び出す上に正しい幅が計測できないんだよなあ! これには参ったよ。



一個ずつ仕留めれば倒せる。どんな生物でも170°のガーリック油で煮れば死ぬ。wikiで見た。あーーー茹でガニくいてー。



よいTMPro生活を! よいライブラリなので。





wrote 2020/05/16 23:51:40

EndPointSelector for Autoya


概要

アプリで使うURLを変えたいな~ってことあるじゃない、

ワールドワイドなアプリとかがこう、何かしらの近いエッジを選ぶためにアプリ内部のURLを挿げ替える、的な。


あれをAutoyaに実装した。



EndPointSelector

このリリースで実装されてる。

https://github.com/sassembla/Autoya/releases/tag/0.9.14


IEndPointを実装したクラスを作る + そのインスタンスを渡すフローがAutoya内に構築してあるので、めっちゃ使いやすい。


比例してOverridePointsに多量のメソッドが増えている。



wrote 2020/04/29 2:42:02

iOS/Androidで、UnityからTweetとかをこう


概要

みんなの端末に入っているTwitterを使って~Unityから~呟きたいじゃないかー。

できればApp上にオーバーレイで表示されてほしい。そう。


Twitterのトークン持ってるAppであれば、App内からTorikiとかを使って簡単にTweetできる。やったね。

だが、まあ、それ以外のニーズも存在するよなあ。っていう。



以下メモ。


iOS

シェア済みの確認

https://qiita.com/tetsuhama/items/6a89a490ec7faeebc06f



Activityで表示するAppの限定化

https://qiita.com/hiroshido/items/a7899012d78b65a22021



コンテンツをツールごとに変える

https://www.lanches.co.jp/blog/10776



コールバックは取れるから、Twitterだったかどうかとかまではわかる。

まあわかるだけだなー、TweetIdとかはわからない。



Android

動くけど、ブロックしちゃうのが気に食わない。

http://nirasan.hatenablog.com/entry/2014/12/24/105737


TwitterAppが入っているかどうかがわかるとかいろいろある。

https://gist.github.com/ueno-yuhei/2892e9be68a567d4ca52



wrote 2020/04/07 10:55:43

UnityUI用いい感じレイアウトライブラリ LayouTaro


概要

UUebVIewで大概人生においてのレイアウトエンジンを実装してみようミッションはこなしたはずだったが、

なんか必要があって実装した。


これ

LayouTaro

https://github.com/sassembla/LayouTaro



・Unityで扱えるUIを型で定義、生成し

・それを可変長引数に放り込むとレイアウトされる


というもの。

サンプルとして画像とテキスト、ボタンが使えるようにしてある。



動機

HTMLを書いて独自タグ定義すればいける、というのを目指したUUebViewは、あれはあれで一定の成功を収めている。

が、まーぶっちゃけ「Web専用の固定されたレイアウトを行う」ことに特化していて、自由度はない。


反面、ルールさえ書ければ独自のレイアウトができる、みたいな機構が欲しいというニーズは根強く存在していて、今回はこれを叶えたい。


・タグ定義ができて(LTElement)

・レイアウターを作成すれば

・独自タグで独自レイアウトができる

これが理想。で、かなりいい線まで、非常に小さいコードベースで行けたと思ってる。

文字だろうが画像だろうがボタンだろうが、所詮はTextとRectなので、それをレイアウトしたい、という比較的ベーシックな欲求も叶えられれば、

このタグはこういうレイアウトにしたい、必ず上に表示されて欲しい、ツールチップみたいにマウスオンしたら、、みたいなマニアックな要望まで、

LayouTaroは(しちめんどくさいレイアウトを書くことに人生を捧げるだけで)叶えてくれる。


Textとは、「連続する要素がレイアウト位置に応じて変形、改行される」もの。主に文字。

Rectとは、「要素がアトミックでレイアウトによる変形がない」もの。主に画像とか。



構成

LayouTaroアセットの全体的な構成は次の3層。

・レイアウトまでのフローをフレームワーク化したLayouTaro

・独自タグ(LTElement)

・LayouTaroで動かせるレイアウター


LayouTaroが提供するフローに則ると自作のタグを自作のレイアウターでレイアウトすることができるよ、という感じ。

右向き行単位での縦揃えと左下への改行を行う、という基礎的なレイアウト機能は、実装例を兼ねてBasicLayoutFunctionという名前で組み込み機能として定義されている。


読んでもらえばわかるが、レイアウトとはかなりファンキーだ。まあ、これはまだそれなりにかんたん。


独自のUIパーツを作った時に、それをどう並べるか、各要素が内容によって伸び縮みしたらどうなるか、

そういうのを解決していって欲しい。



使い方


1. 型の定義

    public enum LTElementType

    {

        Box,

        Image,

        Text,

        Button

    }

自分が足したいコンテンツの識別子(LTElementType)を LayouTaro/LayouTaroElements/LayoutElementType.cs に書く。



2. LTElementの定義

public class ButtonElement : LTElement, ILayoutableRect

{

    public override LTElementType GetLTElementType()

    {

        return LTElementType.Button;

    }


    public Image Image;

    public Action OnTapped;


    public static ButtonElement GO(Image image, Action onTapped)

    {

        // prefab名を固定してGOを作ってしまおう

        var prefabName = "LayouTaroPrefabs/Button";

        var res = Resources.Load(prefabName) as GameObject;

        var r = Instantiate(res).AddComponent<ButtonElement>();


        r.Image = image;

        r.OnTapped = onTapped;


        // このへんでレシーバセットする

        var button = r.GetComponent<Button>();

        button.onClick.AddListener(() => r.OnTapped());


        return r;

    }


    public Vector2 RectSize()

    {

        // ここで、最低でもこのサイズ、とか、ロード失敗したらこのサイズ、とかができる。

        var imageRect = this.GetComponent<RectTransform>().sizeDelta;

        return imageRect;

    }

}


UI要素として、LTElementを継承したクラスを定義する。LTElementはMonoBehaviourを継承しているので、このスクリプトはファイル名とクラス名を一致させる必要がある。


GetLTElementTypeで先ほど定義したLTElementTypeを返すコードを書く。


定義するUIパーツがRect(矩形)なのかText(文章)なのかで、追加で実装すべきインターフェースが決まる。

ここでは、画像を使うUIパーツを定義したいので、ILayoutableRectを持たせる。


で、このクラスをAddComponentした状態のGameObjectを返す関数を定義すると、あとが楽。



3. RootElementの定義

2と同様、LTRootElementを継承した型を作成する。

LTElementと異なるのは、GetLTElementsというLTElementのarrayを持たされること。

public class BoxElement : LTRootElement

{

    public override LTElementType GetLTElementType()

    {

        return LTElementType.Box;

    }


    public override LTElement[] GetLTElements()

    {

        return elements;

    }


    private LTElement[] elements;


    public Image BGImage;// 背景画像、9パッチにすると良さそう


    public static BoxElement GO(Image bg, params LTElement[] elements)

    {

        var prefabName = "LayouTaroPrefabs/Box";

        var res = Resources.Load(prefabName) as GameObject;

        var r = Instantiate(res).AddComponent<BoxElement>();


        r.BGImage = bg;

        r.elements = elements;


        return r;

    }

}



4. UIの生成とレイアウト

独自定義した要素を生成、Rootを親として子供要素をガンガン入れる。


        // データ構造を作る、自由に構造を書いていい。

        var box = BoxElement.GO(

            null,// bg画像

            () =>

            {

                Debug.Log("ルートがタップされた");

            },

            TextElement.GO("hannin is yasu! this is public problem! gooooooooooooood"),// テキスト

            ImageElement.GO(null),// 画像

            ButtonElement.GO(null, () => { Debug.Log("ボタンがタップされた"); })

        );


        // レイアウトに使うクラスを生成する

        var layouter = new MyLayouter();


        // コンテンツのサイズをセットする

        var size = new Vector2(200, 100);


        // レイアウトを行う

        var go = box.gameObject;

        go = LayouTaro.Layout<BoxElement>(

            canvas.transform,// レイアウトしたものを置く親のTransform

            size,// レイアウトするビューのサイズ。横幅はそのまま、縦に延びるのを想定している。

            go,// LTRootElement型を継承しているT型のComponentがセットされているGameObjectを指定する

            layouter// レイアウトに使用する操作法をセット

        );


こうして生成された、自由な順番 + 内容でLTElementを含んだboxと、自由にレイアウトを記述できるILayouterを拡張したMyLayouterのインスタンス、そして

コンテンツをレイアウトするためのサイズを用意する。


最終的に LayouTaro.Layout<LTRootElement型> メソッドを実行すると、LTRootElementを拡張した型のGameObjectの中身がレイアウトされる。


上のやつだと、

・幅200のコンテンツに、BoxElementを親として、子コンテンツとしてText(犯人はヤス)、Image(null)がレイアウトされる

という感じになる。



レイアウトコード

ILayouterを実装したクラスのメソッドがレイアウト時に自動的に呼ばれる。

そこで、自力で種類単位でのレイアウトをしてもよし、予め用意されているBasicLayoutFunctionsを利用することも可能。


ILayouterには次の2つのメソッドが定義されている。


Layout関数はLayouTaroのLayout関数から呼ばれる。 コンテンツのレイアウトをTypeEnumごとに事細かく描くことができる。

public void Layout(Vector2 viewSize, out float originX, out float originY, GameObject rootObject, LTRootElement rootElement, LTElement[] elements, ref float currentLineMaxHeight, ref List<RectTransform> lineContents)



UpdateValues関数はLayouTaroのRelayoutWithUpdate関数から呼ばれる。 レイアウト済みのオブジェクトに対し、任意の値をセットすることができる。

public void UpdateValues(LTElement[] elements, Dictionary<LTElementType, object> updateValues)



試しにLayouterを実装してみた場合の全体は以下のようになる。 ILayouterを継承している。

public class MyLayouter : ILayouter

{

    /*

        子要素をレイアウトし、親要素が余白ありでそれを包む。

    */

    public void Layout(Vector2 viewSize, out float originX, out float originY, GameObject rootObject, LTRootElement rootElement, LTElement[] elements, ref float currentLineMaxHeight, ref List<RectTransform> lineContents)

    {

        var OutsideSpacing = 10f;

        originX = 0f;

        originY = 0f;


        var originalViewWidth = viewSize.x;


        var viewWidth = viewSize.x - OutsideSpacing * 2;// 左右の余白分を引く


        // MyLayputrootとしてboxがくる前提で作られている、という想定のサンプル

        var root = rootObject.GetComponent<BoxElement>();

        var rootTrans = root.GetComponent<RectTransform>();


        for (var i = 0; i < elements.Length; i++)

        {

            var element = elements[i];


            var currentElementRectTrans = element.GetComponent<RectTransform>();

            var restWidth = viewWidth - originX;


            lineContents.Add(currentElementRectTrans);


            var type = element.GetLTElementType();

            switch (type)

            {

                case LTElementType.Image:

                    var imageElement = (ImageElement)element;


                    BasicLayoutFunctions.RectLayout(

                        imageElement,

                        currentElementRectTrans,

                        imageElement.RectSize(),

                        ref originX,

                        ref originY,

                        ref restWidth,

                        ref currentLineMaxHeight,

                        ref lineContents

                    );

                    break;

                case LTElementType.Text:

                    var newTailTextElement = (TextElement)element;

                    var contentText = newTailTextElement.Text();


                    BasicLayoutFunctions.TextLayout(

                        newTailTextElement,

                        contentText,

                        currentElementRectTrans,

                        viewWidth,

                        ref originX,

                        ref originY,

                        ref restWidth,

                        ref currentLineMaxHeight,

                        ref lineContents

                    );

                    break;

                case LTElementType.Button:

                    var buttonElement = (ButtonElement)element;


                    BasicLayoutFunctions.RectLayout(

                        buttonElement,

                        currentElementRectTrans,

                        buttonElement.RectSize(),

                        ref originX,

                        ref originY,

                        ref restWidth,

                        ref currentLineMaxHeight,

                        ref lineContents

                    );

                    break;


                case LTElementType.Box:

                    throw new Exception("unsupported layout:" + type);// 子のレイヤーにBoxが来るのを許可しない。


                default:

                    Debug.LogError("unsupported element type:" + type);

                    break;

            }

        }


        // 最終行のレイアウトを行う

        BasicLayoutFunctions.LayoutLastLine(ref originY, currentLineMaxHeight, ref lineContents);


        // サイズを調整する

        rootTrans.sizeDelta = new Vector2(originalViewWidth, Mathf.Abs(originY) + OutsideSpacing * 2);// オリジナル幅で、高さに対して2倍分の余白を足す。


        // 子要素の余白分の移動

        foreach (var e in elements)

        {

            var rectTrans = e.GetComponent<RectTransform>();

            rectTrans.anchoredPosition = new Vector2(rectTrans.anchoredPosition.x + OutsideSpacing, rectTrans.anchoredPosition.y - OutsideSpacing);// ルートの下のエレメントの要素をスペース分移動する。y-なので-する。

        }

    }


    public void UpdateValues(LTElement[] elements, Dictionary<LTElementType, object> updateValues)

    {

        foreach (var e in elements)

        {

            switch (e.GetLTElementType())

            {

                case LTElementType.Image:

                    var i = (ImageElement)e;


                    // get value from updateValues and cast to the type what you set.

                    var p = updateValues[LTElementType.Image] as Image;

                    i.Image = p;

                    break;

                case LTElementType.Text:

                    var t = (TextElement)e;


                    // get value from updateValues and cast to the type what you set.

                    var tVal = updateValues[LTElementType.Text] as string;

                    t.TextContent = tVal;

                    break;


                default:

                    break;

            }

        }

    }

}



実例

スクリーンショット 2020-03-24 18.14.10.png

こんな感じのレイアウトができたりする。はい。



いい感じ。

wrote 2020/03/23 22:44:12

Unityが提供しているSign in with Apple(SIWA)のコードを調整してまともにする


概要

まずい。Unityが提供しているSIWAのコードをそのまま使うと、脆弱性があるんで殴られまくり、最悪やらかしアドベントカレンダーにInすることになる。


問題があるUnity製のSIWAライブラリはこれですね

記事

https://blogs.unity3d.com/jp/2019/09/19/support-for-apple-sign-in/


記事で紹介されてるパッケージのURLはこれ

https://assetstore.unity.com/packages/tools/sign-in-with-apple-154202?_ga=2.99623134.1148277808.1584082182-434679709.1581905190


最終更新が2/14とかなんだけど、修正されてない。



ここで紹介する問題はすべてUnityが用意しているUnityクライアントSIWA用のObj-Cコードに由来する。


問題点は以下

・nonceを扱っていないのでリプレイアタックされ放題になる

・nonceを扱っていないので出元の確認ができない

・AuthorizationCodeを扱っていないので検証がしょぼい気がする(検証中)



nonceを扱ってないのの何が問題か

・おんなじデータをexprが切れる前に投げ放題

・サーバ側がJWTを検証する材料が不足する


ひとえに、せっかくSIWA自体の機構がnonceを使うことを推奨しているのに、それを使わないので脆弱になっている。



SIWAのnonce

iOS13以降に入っているASAuthorizationAppleIDProviderでは、リクエストの生成時にnonceパラメータをセットすることができる。

これは、任意の値をnonceパラメータにセットし、そのパラメータがリクエストの成果物に含まれることを意味する。

例えばサーバでnonce1を生成、クライアントがそれを受け取りnonce1をnonceパラメータにセットすると、Appleから返送されてくるデータにnonce=nonce1が入る。


これによって、クライアントがサーバへと認証データを送った際、サーバ側はnonceに何が含まれているかという情報で検証することが可能になる。

まーーーこれがないと、サーバ側は「jwtのフォーマット的には正しいが、それ以外に検証要素がない」という状態に陥る。



nonceの追加

で、Unityが提供しているSIWAライブラリにはnonceをセットする部分がゴッソリ抜け落ちているんで、足したものがこちら。

Autoya Thirdpary Authentication

https://github.com/sassembla/Autoya/blob/feature/signinwithapple/Assets/Autoya/ThirdPartyAuthentication/SignInWithApple/Plugins/iOS/SignInWithApple.m#L59


        request = [provider createRequest];

        [request setRequestedScopes: @[ASAuthorizationScopeEmail, ASAuthorizationScopeFullName]];


        // set nonce for verification.

        [request setNonce:nonce];


これでnonceがセットできる。C#側のコードからのセットまで当然可能になってる。


で、これでsignup/signin時にnonceをセットすると、Appleが返してくるidToken(JWT)のpayloadにnonceが入るようになる。


例えば db862182-d25b-44f7-ae26-8c11437c1d80 という値をnonceに入れてsignup/signinを行うと、次のようなJWT payloadが帰ってくる。太字のところがnonce。

{

  "iss": "https://appleid.apple.com",

  "aud": "com.kissaki.app”,

  "exp": 1584132002,

  "iat": 1584131402,

  "sub": “xxxxx.xxxxx”,

  "nonce": "db862182-d25b-44f7-ae26-8c11437c1d80",

  "c_hash": "VUbmqVL9jkYt5VpBCtWkhQ",

  "email": “xxxxx@x.x”,

  "email_verified": "true",

  "auth_time": 1584131402,

  "nonce_supported": true

}



んでーー、これを検証するnode.jsのコードはこんな感じになる。太文字のところがnonce関連。

事前にAUDIENCE_CLAIM(Appのidentifier)、

ID_TOKEN(検証したいidToken、クライアントでSIWAが成立したら出てくるやつ)、

NONCE(クライアントでSIWAのSignup/Signinをする際に入力したやつ) を入れておく。


verify.js

const AUDIENCE_CLAIM = "com.kissaki.app”;

const ID_TOKEN = “xxxxx.xxxxx.xxxxx”;

const NONCE = “xxxxx”;// nonce should be issed and recoded by the app-server and the client app should use it for SIWA signup/signin.




const jwt = require('jsonwebtoken')

const jwksClient = require('jwks-rsa');


var client = jwksClient({

  jwksUri: 'https://appleid.apple.com/auth/keys'

});

 

function getApplePublicKey(header, callback) {

  client.getSigningKey(header.kid, function (err, key) {

    var signingKey = key.publicKey || key.rsaPublicKey;

    callback(null, signingKey);

  });

}

 

jwt.verify(ID_TOKEN, getApplePublicKey, null, function (err, decoded) {

  if (err) {

    console.error("validation err:" + err);

    process.exit(1);

  }

  if (decoded.nonce !== NONCE) {

    console.error("unexpected nonce (nonce claim): ", decoded.nonce);

    process.exit(1);

  }

  if (decoded.iss !== "https://appleid.apple.com") {

    console.error("unexpected issuer (iss claim): ", decoded.iss);

    process.exit(1);

  }

  if (decoded.aud !== AUDIENCE_CLAIM) {

    console.error("unexpected audience (aud claim): ", decoded.aud);

    process.exit(1);

  }


  console.log("succeeded to validate Apple token: ", decoded);

});


検証に成功すると次のようなログが出る。

succeeded to validate Apple token: {

  iss: 'https://appleid.apple.com',

  aud: 'com.kissaki.app‘,

  exp: 1584139641,

  iat: 1584139041,

  sub: 'xxxxx',

  nonce: '8a12db08-1e5f-4bbf-83be-4220abb3c55d',

  c_hash: ‘xxxxx’,

  email: ‘x@x.x’,

  email_verified: 'true',

  auth_time: 1584139041,

  nonce_supported: true

}


検証に失敗する場合はその理由が出る。


注意して欲しいのは、上のコードはあくまで手元のnode.jsを使って検証してみよう的なホビーコードだってこと。

実際にはJWTに含まれているnonceについて、サーバ側でそのnonce値が正しいものか、すでに1度使われたものではないか、というのを確認する必要がある。

なので~上のコードとはかなり違ってくる。


で、nonceパラメータをサーバサイドが発行するごとにユニークに変化 + 記録すれば、

・既に使われたnonceが来たら殴れる

・検証の材料にできる


という、まあ、はい。普通ですね。



これでやっと、Androidの課金検証と同レベルの検証ができるようになった、、はず。

nonceには何を入れても(なんか長さ制限とかはRFCとかにあると思うが)いいはずなんで、リプレイアタックの防止と、JWT検証の助けにしようね~。



AuthorizationCode関連

Unityが配布しているSIWAのコードに入ってなかったのは、nonceだけではなく。

AuthorizationCode と呼ばれるパラメータもObj-C側のコードで無視されていた。


んでーーこれーー、なんかrefresh tokenとかが取得できると思ってるんだけど、設定が膨大なんでまだ確認できてない。

AppleのサーバにAuthorizationCodeを使って問い合わせて、200が帰ってくればOK~という認識なんだけど、途中。



危機感が出てきたら続きを書く。


昨今のAndroidの課金周りとかが壊滅的な改竄を受けてる(ので、なんかチート防止ツールの価値がより強固になってる)のがかなり残念という認識を持ってるんで、

や~~っぱ通信しましょうよー~~みたいなことを言い出す気がする。自分は。



参考

調べるにあたって、このへんを参考にした。

Apple

JWTのverifyの話 nonceはここでも紹介されてる。

https://developer.apple.com/documentation/signinwithapplerestapi/verifying_a_user



Sign in with Apple を本番でやらかしをしないために考えてみた

最も参考にした記事。もっと読み込まないといけない。

https://nerocrux.hatenablog.com/entry/2019/12/11/163231



What the Heck is Sign In with Apple?

AuthorizationCodeをverifyするための設定の話を書いてくれてる。読んでる。

https://developer.okta.com/blog/2019/06/04/what-the-heck-is-sign-in-with-apple





wrote 2020/03/14 6:48:33

Tensorflow実験 


概要

なんか社内にあった本に合わせてやってみる。

anacondaインストール

https://www.anaconda.com/distribution/


エラーは出るけどインストールできる。

updateは conda update conda


スクリーンショット 2019-11-25 15.17.30.png

この矢印から開始、Terminalとかが起動できる。


anacondaのterminalへとconda install Xでいろいろ入れる。

jupyterとかもここで入れる。


anacondaのterminalからJupyter notebookを起動、new -> python を選んで、実行できる環境が立ち上がる。


a = tf.constant(1, name = ‘a’)// tensorを定義

b = tf.constant(2, name = 'b')

c = a + b// 足し算


with tf.Session() as sess:

    print(sess.run(c)) // 3


graph = tf.get_default_graph()

print(graph.as_graph_def())// グラフ定義のデータが出力される


ここで、sess.runするまでは一切の計算が行われていない状態になっている。 = データフローグラフ

Sessionは値が保持されている期間を指している。



可視化

kerasを使ってデータをDLし、matplotを使ってビジュアライズ。



import keras

(x_train, y_train), (x_test, y_test)= keras.datasets.boston_housing.load_data()

%matplotlib inline

import matplotlib.pyplot as plt

plt.rcParams['font.size'] = 10*3

plt.rcParams['figure.figsize']  = [18,12]

plt.hist(y_train, bins=20)

plt.xlabel('価格')

plt.ylabel('count')

plt.show()


こんな感じのコードで特定の値を取り出してビジュアライズできる。


続きを読んでく。



wrote 2019/11/25 11:25:07

GoでWebサイト作る


概要

このへんを見て学ぶ

https://blog.a-know.me/entry/2017/12/26/234528


最終的にはDockerとかでやろう。



GOROOTってなーに

Goのインストールパス。


GOPATHってなーに

プロジェクト置き場。

ここの下に置かないといけないのなんでなんだろ、ちょっとわからんので調べよう。

-> workspaceだからとのこと。なるほど。



go install コマンドは何をしてるの?

binフォルダ以下にバイナリができる。

パッケージのコンパイルと依存性解決、というのがinstallコマンドの役割ぽい。



go build

goのコードをその場でビルドできる。依存性解決とかやるにはgo getとかやる必要がある。

installはそのへんを自動化してくれるのかな。


http://imagawa.hatenadiary.jp/entry/2016/12/24/190000

-> 正解っぽい。



ChitChat編


コードがすでに完成されているものを見るしかないのがわかった。どうやって切り捨てていこうかなー。

git化した。



続きをやっていく、そろそろDBに入る!

ここでいうThreadとは多言語のスレッドのことではなくチャットのスレッドのこと。

Postgressapp入れてpostgress動かす。


Postgressapp.comからDL、


export PATH=$PATH:/Applications/Postgres.app/Contents/Versions/latest/bin


で接続できるように。

psql --version

psql (PostgreSQL) 12.1


Postgress.app上でInitializeってやると初期化開始できた。


createdb chitchat 

をコマンドラインで実行した結果、

スクリーンショット 2019-11-29 10.05.00.png

こんな感じになった。

で、次のsetup.sqlファイルをpsqlコマンドで実行すると、-dで設定したデータベースに対してsql文が発行される。


psql -f data/setup.sql -d chitchat


drop table posts;

drop table threads;

drop table sessions;

drop table users;



create table users

(

  id serial primary key,

  uuid varchar(64) not null unique,

  name varchar(255),

  email varchar(255) not null unique,

  password varchar(255) not null,

  created_at timestamp not null

);


create table sessions

(

  id serial primary key,

  uuid varchar(64) not null unique,

  email varchar(255),

  user_id integer references users(id),

  created_at timestamp not null

);


create table threads

(

  id serial primary key,

  uuid varchar(64) not null unique,

  topic text,

  user_id integer references users(id),

  created_at timestamp not null

);


create table posts

(

  id serial primary key,

  uuid varchar(64) not null unique,

  body text,

  user_id integer references users(id),

  thread_id integer references threads(id),

  created_at timestamp not null

);

users, sessions, threads, postsなどのテーブルが作成される。

それぞれidがあって、みたいな構造になってる。


で、これにアクセスするDbインスタンスを作る。

db connect errsql: unknown driver "postgres" (forgotten import?)


コードを実行するとこんな感じのエラーが出た。

で、すでにimportされてるdatabase/sqlはこれ汎用SQLのドライバーで、その下層に位置するべきpostgresのドライバがimportされてなかった。

go get github.com/lib/pq


で解決した。importだと解決できなかった(解決されなかった)のなんでだろう。



DBについて

https://qiita.com/H-A-L/items/fe8cb0e0ee0041ff3ceb

ここをみてポスグレについて学んでいる。


/Applications/Postgres.app/Contents/Versions/12/bin/psql -p5432 “chitchat”

みたいなコマンドでchitchat DBにログイン、


select * from users;


とかでユーザー一覧を取得。


chitchat=# select * from users;

 id |                 uuid                 | name | email |                 password                 |         created_at         

----+--------------------------------------+------+-------+------------------------------------------+----------------------------

  1 | 31467eda-ae54-47e6-5a41-25cbee98e6ad | a    | a@a.a | df51e37c269aa94d38f93e537bf6e2020b21406c | 2019-12-04 15:44:49.768178


こんな風に取得できる。あとは条件をいろいろorder byとかで決めれば良さそう。語句はぜんぜん覚えられないな、、へんな法則してそう。



Queryについて、

err = Db.QueryRow("select id, uuid, email, user_id, created_at from sessions where uuid = $1", session.UUID).Scan(&session.ID, &session.UUID, &session.Email, &session.UserID, &session.CreatedAt)


こんな感じに書くと、from句の前に書いた情報のうち、where句に該当する = uuidが指定したものと一致するデータが取得でき、Scanメソッドで代入させられる。


さて、privateには入れた = ログインの概念が理解できたんで、次いってみよう。スレッドどうやって作るの? UI足りてなくない?

-> テンプレートエンジンにcontentを足すと表示できた。生成もOK。



で、ここからどうするか。とりあえず全体を流し読みしよう。











wrote 2019/11/24 17:05:44

Deformのコードを読んでみる


概要

これ

https://www.fast-system.jp/unity-deform-1-0-assets/



読んでみたとこ

JobSystemで動いている。で、計算は「頂点を目標点に動かす」という感じで動作している。

CPUだけを使った頂点移動で、まるごと全ての点を移動している。

これを応用するには、

・インデックスで点AからBの間はこの変形

みたいな応用をすると良さそう。indexの集合を作って集合ごとにIJobParallelForに放り込むとかそんな感じか。



wrote 2019/10/29 0:10:43

Chanquo2系


概要

Chanquo = Typeを接続用パラメータとして扱うGoのchannelもどき for Unity。


1系は正直適当な実装だったんで、goのコードを読みながらアップグレードを目論む。

互換性は破壊されちゃったらごめんねみたいな想定。->破壊されました。やったぜ!


1系のダメなところ

・structを使えない(致命傷)

・マルチレシーブが特に必要ない感じ(タイムアウトとかがつけば別だが、それはそれで変な実装になる。

・yield returnしたい(一件受けたら云々とか)

・スロットルの概念があってもいい(N個をまとめて受ける)

・MainThreadDispatcher頼み(シーンを超えられるが、超えていいケースは少なかった。)

・コードが汚い(美しくない、拡張性が低い)

・Jobまわりを綺麗にアレしたいができない


ということで、2系の開発に取り組み、完成した。

Chanquo

https://github.com/sassembla/Chanquo



対応し途中のもの

・スロットルの概念があってもいい(N個をまとめて受ける)

・Jobまわりを綺麗にアレしたいができない


これらは途中。で、これら以外は対応できた。



結果

こんな感じの書き方ができるようになった。

var ch = Chan<T>.Make();

ch.Send(new T(){});


struct型Tを指定して、chの生成、chへとデータの送付。

goでの ch <- データ みたいな形。



受け取り側は複数パターンが使えて、


// start receiving data asynchronously.

ch.Receive(

    (T data, bool ok) => {

        // ok will become false when the channel is closed somewhere.

        // when ok is false, data is empty.

    }

);


1. select 文に対するcase data, ok := <- chのような扱い。

非同期で継続的な受け取り。これはv1と同じようなシグニチャになっている。と思ったけどそうでもないか。

誰かがchをCloseするとokがfalseな状態で飛んでくる。



// receive data until Chan<T> is closed.

yield return Channels.For<T>(

    T t =>

    {

        

    }

);


2. こちらはfor文での for data := range ch 相当。

Unityの場合はブロックせずに一定の位置で待つ、というのがasync汚染なしでは辛い(なんかいい手段ある?)という感じなので、

yield return と組み合わせる形にしている。



// wait first data then go through.

yield return Channels.WaitFirst<T>();


3. こちらは単純に <- ch と同じようなもの。

T型のデータがどこかから送信されると、yieldを抜ける。


goの場合はgoroutineでブロックをつくりまくっても全体には影響が及ばないのだが、

Unity C#の場合はブロックするとてきめんに詰む。


そのため、「その位置で待つ」という機能としてyield returnを使っている。


感想

より捨てやすく、なんとなーくUnityフレンドリーな書き方もできるようになった。

structが使えるのもよい。



wrote 2019/10/14 0:01:11

Unite2019Tokyoログ


概要

かなり満足感のある公演がいっぱい聞けた。が、めちゃくちゃ抜粋だけ。



The Heretic

VFXGraphで、キャラクターの周りに球体の判定を作り、その判定に対してホコリが避けるようなのを作る

すごいな、こんなことまでできるんだ。


符号付きディスタンスフィルタ(SignedDistanceFilter)

エッジに近づくほど黒くなる的なマスクに使っていた。TextMeshProでおなじみ。


ワープ

異常な量のスライダーがあって面白かった。

基本的な考え方としては、なんらかの単位で映像をスライス、ずらしたり歪めたりしていた。


たのしいDOTS

いますぐはじめなくてもいい DOTS。プレビュー版。


メモリ -> 土地、面積。出来るだけ効率よく使いたい。

中央管理者の関与なしに場所から別の場所(=アドレス)を指せるので、コントロールが厳しくなる。

みたいな歴史があって~。


そこで、NativeContainerという概念を使って、unmanagedな領域で頑張る。

C#の仕様上で、structはmanaged領域に入らないのを利用した構成。


チャンクの話

chunk = GameObject、というか「インスタンス」。


昨今の端末はメモリ的に富豪なので、managedな領域で頑張らなくても、unmanagedな領域で富豪的にやってみてもいいのでは?

ということで、


チャンクは16KB単位。これは固定で、「この単位で管理する」というだけの決まり。

一つ要素を消すには、

・穴を開ける

・穴に対していままで他のところにあったデータをコピーする

(このとき管理系も書き換える)

とかで、たったの2ステップで完了する。



UnityPhysicsの話

決定性がある(マルチスレッドでなおかつ状態を持たないのでマジで単なる式として動く)

シミュレーションループ独立



予測系が実装できる(ゴルフの玉がどう飛ぶかとか)


・ABとかはどうなるの?

-> ECSへとダイレクトロードできるようになるはず(システムの組み合わせとかは前提になる)


Rig Constraints

・packageに上がってる(preview)

・実行時にいろいろできそうなやつ。サンプルが入ってるので触ってみよう。


モーションなどのブレンドができる。



感想

1日目は基調講演とかみれた感じ。


感想というか気になった点は、

・ECSはまだこれからもっと書きやすくなる by 安原さん


という感じで、

エンティティとかシステムを使ってまるーーっと書き方が変わるところとどう使い方が変わるか、待とうね!!! というのが総論。


Day2 

SRPの話

SRPってなーに? Unityの描画フローについて自作できる機構。


投影テクスチャシャドウが使いたい!

Unityのシャドウマップは必ずデプスバッファになる。

-> デプスバッファを使わずにR8程度でシャドウマップを持ちたいが、変更はできない。カメラとかで描画を自作して自分で、、、しんどい。

-> なので、SRPで、、、



RenderTextureとカメラ管理

prefabをつくってー、RenderTexture関連のスクリプトを置いてー、、

-> Playしないと絵が出ない、各要素にスクリプトが必要、生成順の問題が、、、

-> なので、SRPで、、(これはまあ意図が影響してるが


作り方

Protected override void Render(…)みたいな関数を書くと上書きされる。

サンプルは近日公開。


書き方: LWRPを参考にしよう! 中身を見る以外に特に例はないぞ。マジか。

これスペックどうなるんだろう、まー変わんないのか。


いいところ

・単一のカメラで縮小したRenderTextureをdepthありで生成したり、それらの描画をマージしたりができる


Unityの描画機能をimportするには?

reflection probeを実現するための関数があった。

PostProcessingStackを使いたい -> PostProcessingRenderContextというのがコードから利用できたので、それでコンテキストを作成して、、


UnityのデフォルトUIはそのまま描画したい -> UIにはライトがない。DefaultUnlitというのを設定するとできた。


-> 困ったらすべてLWRPの該当の箇所を見てる。



結論

パイプライン外部でカメラ + RenderTexture自作ではなくカメラ一発で済むの最高!



セガのHTTP/2の話

HTTP/2ライブラリの実装について

・C/C++は避けたい、、

・HTTP/2のC#実装を探した

・monoとか色々あるけど結局C#で複数をサポートしているのがなかった

・C#を断念

・もうC/C++しか、、

などの感じで、最終的にlibcurlをラップして使う形になっていると。

これはWindowsエディタで動作するいい感じのライブラリがなかったため。

Windowsエディタが要らない + iOS/Androidならそれぞれのネイティブがいいのでは?ということを言っていた。


HTTP/2あるあるなんだけど、切断検知やタイムアウトについて、

・libcurlのコネクションそのものに対するタイムアウト+R/Wに関するタイムアウト

・これだけだと足りなくて結局C#側でもタイムアウト検知してる


などがあるとのこと。



禍つヴァールハイト」最大100人同時プレイ!モバイルオンラインゲームの実装テクニック

次のようなリソース管理を行っているぽい。

・ABをビルド

・すべてのABをtarファイルで連結、どの部分にどのABが入っているかなどのリストを作成(tarのインデックス集)

・tarとリストをCDNに置く

・クライアントはリストを取得、クライアント内のキャッシュと比較して、ABが必要になったらCDNから取得する

・CDNへのリクエストとしてrange指定を行い、tarファイルから特定の範囲を取得する

(複数のABの取得が1リクエストでできるというおもしろ効果がここで発生する

・クライアントはレスポンスを事前に取得していたリスト情報をもとにN個のABに分割、ローカルフォルダに保存

という感じで、

なるべく少ないリクエストで複数のデータを取得する、というのを実現している。すごい。



Untiy ロードマップ

LiveLink

ビルド済みアプリに対してエディタからデータを送り込む、今後はコードも(ホットリロードかな!??!

開発中だけでもiOSで使えると嬉しいな。



テクスチャストリーミング

テクスチャを非同期でロードする技術。

特にVRとかで、至近距離なら高精細なテクスチャ、遠くなら荒いやつ~とかで大活躍しそう。

今後が楽しみ。


Cloud Content Delivery

Unityが手配してくれるCDN的なもの。

まだいろいろ未定とのことなんで、Akamaiさんとかと組んでくれると嬉しいなあ。



wrote 2019/09/25 11:27:26

mac版 本来ならUnityEditorが獲得すべき権限をUnity Hubが取得しようとする件


概要

Unity Hub経由でエディタを起動し、エディタから実行するアプリに権限を求めるようなものがあった場合、

その権限はUnity Hubに組みつくようだ。


実際どうなるのか

まず、Unity Hubからエディタを起動(なんかのプロジェクトを開く)


そんで、まあ、一般的なエディタの、こういう画面から。

スクリーンショット 2019-07-26 16.57.41.png



例えばカメラにアクセスするようなアプリをエディタでPlayすると、こういう表示が出る。

EAYIfLaVUAIvSlT.jpeg


脳みそびっくりしません? 今俺はUnity Editorを触っていて、Playを押して、しばらくしたら(カメラを使うところまできたら)こういうのがいきなり出るんだよ。


・Unity Hub 

・から

・カメラにアクセス


いやOKしないよね。なにそれってなるでしょ。


Hubからエディタを起動した場合は「”Unity Hub”から」

エディタを直接起動した場合は、「”Unity Editor”から」


そんな感じに文言が変わるんだよね。



で、これは、

・Unity HubはUnity Editorを選択、起動している

・Hub経由で起動された場合、エディタではなくHubがプロセスの主人になっている

とかかな~と思っている。



問題かな?

1つ問題、1つ疑惑があると思っていて。


問題: Unity Hubが~~ って出るのは心臓に悪いからやめろ

はい。これに関しては異論は認めない。



疑惑: これUnityHubが一個しかない + エディタは無数にある、って状態なんだけど、エディタ一個一個の許可がHubに集権されてしまっているのでは?


この疑惑がね~~~気になる。


要は、次のようなストーリーが実現できるのではないか。

1. ユーザーはエディタ 1をインストール

2. Hub経由でそれを起動、写真へのアクセスを求めるコードを含んだプロジェクト(以下プロジェクト)を開く

3. プロジェクトをPlayすると、写真へのアクセスを求められた(Hubから写真にアクセス、、とか出る)

4. ユーザーはこれを許可。

5. ユーザーはエディタ 2をインストール

6. Hub経由でプロジェクトを開く

7. プロジェクトをPlayすると、写真へのアクセスを求められ、、るはずが、そのままアクセスできてしまう(!!??!!?)



これでやだな~~って思うのは、たとえばgithubにある誰かのプロジェクトとかを適当に開いた瞬間にサイレントに意図しない権限許可が発生する、とかが起こせる気がするんだよね。

少なくとも今回俺はこういうケースで引いたんですよ。

(githubから持ってきたProjectを開いてPlayしたら意図せずカメラ使う権限を請求され、えっ請求元がHub!??! オワタの!?? ってなってた。)


そもそもなんでアプリ単位で権限許可が発生するかというと、OSがそういう権限管理を良しとしてデザインされているからなんだけど、


・Hubが権限を持っちゃって、適切に権限操作が行われないのでは??

・Hubをクラックされたりした時、Hubはいろいろな権限を持ってしまっているのでは??



こういう疑惑が俺の中にはある。


まあーー~~~その~~~~ 無様だ。直したい。





wrote 2019/07/26 16:53:08

Unity道場 2019/06/27回


概要

VectorGraphicsで作るエモい表現



以下メモ

SVGインポート

ランタイムでのメッシュ生成


packageManagerからインポート

はい。



円形のSpriteを生成したい。

・図形データの用意

・テッセレーション

・メッシュ生成

このへんを自分でやる。


Scene/

Shape(塗り、線、重なり制御)/

BezierContour(曲線)/

BezierSegment(制御点)….


Clipper()/



VectorUtilsを活用するとよい。



・図形データの用意、曲線を生成する

var shape = new Shape();

shape.~~



・テッセレーション

オプションを設定する。

stepDistance値 で線の荒さが決まる。


で、ジオメトリを生成し、

-> Sprite

-> Sprite -> テクスチャ化

とか、もう2種類あるはず。


単純、規則的なものであればシェーダーの方がよい




こんな感じに文字列をSVGとしてパースできる

SVGParser.ImportSVG(StringReader(string));




SVG1.1準拠

SolidFIll のモードをOddEvenにすると穴として抜くことができる。


VectorGraphicsを使ってマスクを作る

SpriteMaskのマスクスプライトにセットするといい感じに抜ける。




wrote 2019/06/27 20:09:59

UnityのDebug.Logの話(IL2CPPでログを出したいみたいな話を添えて)


概要

個人的にUnityでのLogが実機(iOSとかIL2CPPの果て)で最終的にどうなるか、という動作を追い切ったことがないんで、追った話。



前提

・UnityEditorのLogging設定では、ログは出る。stacktraceが止むだけ。

・UnityEngine.Debug.unityLogger.logEnabled = false; では、実行時にこのコードを実行後、ログは出なくなる。


ここまででいうと、後者、 UnityEngine.Debug.unityLogger.logEnabled = false; いいじゃんってなると思うんだけど、まだ気になるポイントがあった。



発端

UnityEngine.Debug.unityLogger.logEnabled = false; を使っても、Debug.Logの中の実装が変わるだけで、

Debug.Log(“a:” + 1000);

とかの中身が変わってログは出なくなるが、


“a:” + 1000 の部分は、“a:” + 1000.ToString() みたいな処理が走る。


処理が走るやんけ、というところで、ToStringは new string ~ みたいなのがその結果として発生するので、

結果としてログ関数の中身を無効化しても、無駄なnew発生してるやんけという話。



before

Debug.Log(“a:” + 1000);


after

UnityEngine.Debug.unityLogger.logEnabled = false;

Debug.Log(“a:” + 1000);// 関数の中身がすげ変わってログは出なくなってるが、1000をstringに変える、という処理は残っている。



これはまあ、“a:” + 1000の部分で発生したToString()の成果が、GCの対象となる。



で、まあ、つまり、

・UnityEngine.Debug.unityLogger.logEnabled = false; をやっても、結局ログコード自体が残っていると無駄なnewが走る


というわけだ。俺はこの時点で結構絶望した。



なんでかというと、UnityEngine.Debug.Log類をglobalで上書きする、という、ヒューマンパワーを食ううえに不完全な方法しか解決策がないから。


どう不完全か

この辺がわかりやすい。

【Unity】リリース時にDebug.Logを出力しないようにする

https://noracle.jp/unity-no-debug/


この記事では、

・自前でUnityEngine.Debugを上書きして

・Conditional属性をつけることで、根こそぎ無効にできる

という手法と、その手法がなお及ばない部分がある、と言うことを示してくれている。


・using A=B とかやられてるやつは対処できない(ライブラリとかにめっちゃある)

ということがそれ。コードならいいけど、dllなら? 詰むが?



そしてそれとは別に、まあ、自分はこっちの方が気になるんだけど、

・毎回誰かが同じ、Debug.Log*系のコードを書かないといけない

これなんの罰ゲームだよ。被ったりするしみんなが同じことを毎回やる必要ないでしょ。


そう、つまり不完全なのだよ。

完全な、デザインされた元栓が欲しいんだ。



こうであってほしい

・コンパイル時にUnityEngine.Debug.LogをConditionalで制御できるようにしてほしい

・そしたらコンパイル時にUnityEngine.Debug.Logを呼んでる箇所は、たとえdllの中でも消えてくれると思うし、

・例えばログのためのローカル変数とかもunused扱いになってコンパイルで消せると思うので



みたいな感じ。ユーザーが書けるC#レイヤーでこういう問題に挑ませるの悪手だと思う。

具体例を書こうか。


こういうコードがあったら、

foreach (var path in deleteTargetPaths)

{

    Directory.Delete(path, true);

    Debug.Log("folder deleted:" + path);

}



もし、Debug.LogがConditionalAttributeとかで実装してあれば、

foreach (var path in deleteTargetPaths)

{

    Directory.Delete(path, true);


}


コンパイル時にこうなったりするはずなんだよ。

するとどうだ、"folder deleted:" + path が関数ごと消えるでしょ。こうなれば関数がどうなってようと関係ないじゃん。幸せでは。



IL2CPP側はどうなっているのか

で、まあ、自分の中での結論は↑の通り、UnityEngine.DebugにConditionalつけといてよ、なのだが、

それはまあなんか言う機会を作って言えばいい話なので、なんならバグレポレベルだと思ってるしそれはそれとして。


今できることはなんだろうか。


例えば、IL2CPPへとコンパイルされた段階で、Debug.Log関数の元締めは世界で一個しかないはずだ。

だから、その関数をIL2CPP上から滅殺できる、みたいなマクロがもしラッパーとして定義されていれば、


その部分をいじることでマクロとしてDebug.Logを消し、Log関数に読み込まれている各種string化処理とかconcat処理とかも、

コンパイラが「お前これつかってないやんけ!!」パワーを発揮して滅殺してくれるのでは!???!? という夢があった。



結論から書くとそれは夢だった。マクロなんかなかった。


IL2CPP世界のログの定義はこんな感じのところにある。

PROJECT/iOS/Classes/Native/Bulk_Assembly-CSharp_0.cpp


(行数に注目するとちょっとクスッとくると思う)

スクリーンショット 2019-06-21 18.10.44.png


さあ、C# UnityEngine.Debug.Logが変換されて出てくるログの関数を探そう。

該当の関数はこれ。

// System.Void UnityEngine.Debug::Log(System.Object)

extern "C" IL2CPP_METHOD_ATTR void Debug_Log_m4051431634 (RuntimeObject * __this /* static, unused */, RuntimeObject * p0, const RuntimeMethod* method);


長えな。

mなんちゃらの数値は、Unityのバージョンに関連なく固定っぽい。特にビルド対象によって変動はしなかった。



そしてこの関数はIL2CPP化されたコードの上で使われてるはずなので、使用箇所を探してみる。


Debug_Log_m4051431634(NULL /*static, unused*/, _stringLiteral223888751, /*hidden argument*/NULL);


こんな感じに、そのままログ関数がコード上で使われている。

マクロとかでラップされてて、マクロを書き換えればあら不思議、なかったことに、、、!! みたいな世界はこの世にはなかった。本当に残念だ。


ここで、「マクロで書かれてれば最悪でもIL2CPPレイヤーでなんとかできるのでは」という夢は霧散する。



IL2CPPでDebug.Logを書こう

最後に、IL2CPPで好きなようにログを書く、という、この世の果てで使えそうなデバッグ手法を紹介しておく。


IL2CPPで出力されたC++コードとは何か、っていうと、あれは、コンパイル結果だ。

断じて人間が何かを書き加えたり、変更を加えられる空間ではない。


で、まあ、


Debug_Log_m4051431634(NULL /*static, unused*/, _stringLiteral223888751, /*hidden argument*/NULL);


とかのコードでは、

_stringLiteral223888751

というポインタにIL2CPP string型みたいなのがあって、そこにC#で書いたC# stringが置かれている。

(実際にはバカでっかい文字列置き場があって、そこにすべての文言が連続する形でキュッと収められている。)



さて、そのIL2CPP string、自力で作ることはできるのか。


できる。


IL2CPP_RUNTIME_CLASS_INIT(Debug_t3317548046_il2cpp_TypeInfo_var);

String_t* a = il2cpp_codegen_string_new_wrapper("comment here!!");

Debug_Log_m4051431634(NULL, (RuntimeObject *)a, NULL);


こんなふうにすれば、comment here!! っていう表示がXcodeとかに出る。

便利でっしゃろ。


IL2CPP世界ではXcodeのbreak pointを置くことでもちろんいい感じにステップ実行できるんだけど、

ポインタのラッパーやラッパーのラッパーがあるせいで、さてここにどうやってジャンプしてきたんだろう、みたいなスタック情報がかき消えているケースが多い。


つまり上から下は見やすいんだけど、

下から上が超絶に見えない。


となると最後の手段はログでしょって感じで、上記のコードが使える。


前提としては、

#include "codegen/il2cpp-codegen.h"

をincludeしている必要があるが、IL2CPPで作成されたコードにはだいたいincludeされてる。



感想

ここまで読まれた人がいたら、ついででいいので読んでおいてほしい。


自分はこう思っている。

・Debug.Logを無効化する方法はいろいろあるが、いまだに完全なものはない。完全なものが欲しい。誰が書いたどんなコードにも適応できる、完全なものが。

・まあ別にstring concatとかToStringとか重たい関数をDebug.Log()のかっこの中で実行してGCがでるくらいいいじゃん、という発想は別にアリだと思っている。

・Debug.Logが一つでもコードに残っているのは悪だ、どんどん消すべき!みたいなのには別に同意しない。

・そんなのは書いたやつの自由だし、なんで製品版ビルドなのにログで損をするんだよという感じ。

・そして、それらとは関係なく、この文脈においてDebug.Logをユーザーに上書きさせることはやはり狂っている。


以上だ。

はい。

wrote 2019/06/20 15:50:44

ARKitRemoteが使いづらかったのでA-npanRemoteというのを作った


概要

発音は[あ~んぱんリモート]。


リポジトリはこれ

https://github.com/sassembla/A-npanRemote

名前にハイフンが使えて大満足。Unity内でも問題なかった。

由来はARです。イニシャルが。



原因

Unity標準のARKitRemoteの、接続をする、ボタンを押す、動作する、、、みたいなのが本当に最悪の体験だった。

なんか切れたり落ちたりするし、接続自体に失敗するみたいなのまである。これではダメだ。こんなダメな体験で人生を無駄にしてはいけない。



ということで目指したのは以下


・エディタ上でARKitを使うコードを書いたら自動的にARKitサーバが立ち上がるようにする

・ARKitを動かすiOSアプリ側からいつでも、何回でも接続、再接続できる

・無線で接続できる。


構造

まず、iOS ARKit実行機からはUnity Editorに接続することにした。

これはまあ、エディタで動いてる時しか使わんでしょみたいな感じ。


接続にはWebSocketを使う。そのため、iOS側にはWSクライアント、エディタにはWSサーバが立つ。


概念的に書くとこんな感じ

iOS ARkit -ws-> Unity Editor


WSサーバは結構軽量なんで、ユーザーがエディタのPlayを押したら起動、Stopを押したら落とす、みたいな感じにした。




次にPlay中にARKitを使うところまできたら &&  iOS ARKitからのインプットが来ていたら、自動的にiOS ARKitのインプットをPlay中のアプリに流し込みたかった。

で、エディタとPlay中のアプリの接続には、やっぱりWebSocketを使った。


概念的に書くとこんな感じ2

iOS ARkit -ws-> Unity Editor <-ws- Player

面白くなってきやがったぜ。


最終的なデータフローとしては、上記を実装した上で、iOS -> Editorで中継してPlayerに流し込む という単純なものになっている。

この構造ならiOS側が切断しようがPlayer側が切断しようが、どちらかが復帰したタイミングでデータを流せる。



展望

現状はただARKitについて動くだけなんで、今後はOculus Questの視界とかコントローラとかをUnity Editorにほうり込めるようにする。

WebSocketサーバで自前のやつがあったんだけど権利の関係でちょっと改修が必要で、現在はFleckというMITライセンスのライブラリに依存している。


MSの用意してるWebSocketサーバのAPI実装はリクエストヘッダ付きのモバイルからの通信に対してちゃんと動作しなかったので無視する。出来が悪い。

みんなSocketを使って実装してるぞ。ハイレベルなAPIなんか使い物にならないから使われてないぞ。俺も使ってないが。君はどうだ。



wrote 2019/05/31 10:03:58

Unity2018系以降でAndroidのビルドのための環境を整える


概要

Javaに関してかなり頑張りたく無いが、OpenJDKはUnityに含まれるようになっている。これはすごい進歩。

が、IL2CPPを使うにはNDKが、そしてそもそも実機インストールするにはAndroidSDKのインストールが必要。




sdkインストール

sdkのインストール自体は、ここからDLできるコマンドラインツールで事足りる。

https://developer.android.com/studio#downloads

スクリーンショット 2019-05-05 21.53.48.png


間違ってもAndroid Studioとか要らない。


DLしたsdkは、zipファイル名をフォルダ名にして、Applicationsフォルダ以下においとく。この場合は、sdk-tools-darwin-4333796。


で、設置が終わったら、Unity > Preferences > External Tools でsdk -> browse とやって、toolsフォルダを指すと設定が完了する。



SDK周りの設定

えーっと、AndroidのSDKは、インストールしただけだと何も入っていない状態なので、特定のバージョンのsdkをインストールする。


sdkmanagerをコマンドラインで動かせば終わりなんだけど、

サクッと動かすためにはJAVA_HOMEの環境変数設定が必須。いやなんか回避できるんだろうけど、今時そういうのダサい、、、はい。


Unityに含まれるjdkのパスを指定する

export JAVA_HOME=/Applications/Unity2018.3.11f1/PlaybackEngines/AndroidPlayer/Tools/OpenJDK/MacOS/



sdkmanagerを起動、欲しいバージョンのsdkをインストールする。

/Applications/sdk-tools-darwin-4333796/tools/bin/sdkmanager --update

/Applications/sdk-tools-darwin-4333796/tools/bin/sdkmanager "platform-tools" build-tools;28.0.2


万が一、億が一、jdkのインストールが必要な場合、

brew cask install homebrew/cask-versions/adoptopenjdk8

とかで、比較的人権を保った状態でJDKを入れられる。まだ捨てやすい。



ndkインストール

Unity AndroidでIL2CPPを使ったアプリを作るには、ndkが必要。

Unity > Preferences > External Tools のとこのndkのDownloadボタンがあるので、dlしたらApplications直下に置く。


設置し終わったら、Unity > Preferences > External Tools の ndk -> browse で、設置したフォルダを指すとOK。




最終的にはこんな感じになればいい。

スクリーンショット 2019-05-05 22.01.00.png



以上。忘れたいので書く。

wrote 2019/05/05 17:45:58

Autoya内からAssetBundleがらみの部分だけを抜き出したモジュールの紹介


概要

これ。

https://github.com/sassembla/Autoya/blob/master/Autoya.AssetBundles.unitypackage


Autoyaはログインから課金まですべからく俺が欲しい機能がいっぱい入っていて、まあ、薄いけどでかい。


そんなにたくさんの機能いらないよ!というのは正直わかる。


なので、まあ、Autoyaは実は複数の機能単位でのモジュールと、それを中央制御するレイヤー(Backyard)でできている。

今回はそれらのモジュールのうち、AssetBundleに関わるものを抜粋したよ、という話。



Autoya AssetBundle Module

ABを生成する部分は含んでいないが、

ABの情報一覧を取得する機構、

AB情報を使って取り出したいAssetを依存関係とか全部みてなんとかする機構、

ABの一覧を更新する機構、


などが入っている。



使い方

1.この世のどこかでABとABListを作ります

2.App内でABListを取得します

3.App内でABに含まれているAssetをロードします


以上! Unloadとかもあるよ。



サンプル

https://github.com/sassembla/Autoya/blob/master/Assets/Packager/AssetBundles/AssetBundlesLoadSample.cs


    IEnumerator Start()

    {

        var LIST_DOWNLOAD_URL = "https://raw.githubusercontent.com/sassembla/Autoya/master/AssetBundles/main_assets/OSX/1.0.0/main_assets.json";

        var ASSET_NAME = "Assets/AutoyaTests/RuntimeData/AssetBundles/MainResources/textureName.png";


        // Download AssetBundle List from web.

        var listDownloader = new AssetBundleListDownloader();


        AssetBundleList list = null;

        var cor = listDownloader.DownloadAssetBundleList(

            LIST_DOWNLOAD_URL,

            (url, newList) =>

            {

                list = newList;

            },

            (code, reason, status) =>

            {

                Debug.LogError("list download error, code:" + code + " reason:" + reason);

            }

        );


        while (cor.MoveNext())

        {

            yield return null;

        }



        // Load Asset from your AssetBundle.

        var loader = new AssetBundleLoader(

            bundleName =>

            {

                var path = "https://raw.githubusercontent.com/sassembla/Autoya/master/AssetBundles/" +

                    list.identity + "/" +

                    list.target + "/" +

                    list.version + "/";

                return path;

            }

        );


        // set list to AssetBundleLoader.

        loader.UpdateAssetBundleList(list);


        var loadCor = loader.LoadAsset<Texture2D>(

            ASSET_NAME,

            (name, tex) =>

            {

                Debug.Log("asset loaded! tex:" + tex);

            },

            (name, error, reason, status) =>

            {

                Debug.LogError("asset load failed. error:" + error + " reason:" + reason);

            }

        );


        while (loadCor.MoveNext())

        {

            yield return null;

        }

    }


MonoBehaviourのStartメソッドを使って、

ABListダウンローダーの初期化 -> 

ABListのダウンロード -> 

ABローダーの初期化 -> 

ローダーへのABListのセット -> 

ローダーで欲しいAsset名、型を指定して、データをロード


と、こういう感じでできる。



ABListの作り方

これはまだちょっとまどろっこしい。

Autoya+AssetGraphパッケージには、ABListのジェネレータも入っているが、その部分はAssetBundle.unitypackageには入っていない。

なので、次のフォルダをゴソッとgithubからダウンロードして、ABを作成したいプロジェクトに含む必要がある。

https://github.com/sassembla/Autoya/tree/master/Assets/Editor

中にはAssetGraphとAssetBundleListGeneratorのコードが入っている。

この状態でAssetGraphを起動し、適当にABを作るグラフを組み立ててビルドを行うと、プロジェクトフォルダにAssetBundlesフォルダが勝手に作られ、ABが生成され、

自動的にABListが生成される。


一度AssetGraphでビルドしたら、ABListにはバージョンという値が振られる。

バージョン値は、Unity上で Window > Autoya > AssetBundle List Version Editor というので変えられる。



スクリーンショット 2019-04-13 21.16.09.png

変えた後でAssetGraphのグラフをビルドすると、そのverのABとかABListが出力される。


生成されたABが入っているフォルダを、どこか、、github上とかにでも置くと、物事が解決できるぞ。


やばくなったらCDNとかでググって。

wrote 2019/04/13 20:57:03

2018.3以降でWebCamTextureがリクエストサイズを無視したデータを投げてくる件(互換性破壊だった)


概要

タイトルの通り。

2018.3.11f1まで、事象が起こるのを確認済み。


同様の問題は2019.1b10でも発生している。



具体的にどうなるのか

iOS端末で、WebCamTextureから取得できるテクスチャサイズが最大サイズのものになる。


例えばiPadPro 12.9 2018モデルだと、2700 x 2000 くらいのテクスチャを返してくる。



対策

WebCamTextureを使わない。



レポート

今作った。



結果

レポートに対して

Hello,


Unity added support for iPhone/iPad Depth Camera, please take a look:

https://docs.unity3d.com/ScriptReference/WebCamTexture-ctor.html

https://docs.unity3d.com/ScriptReference/WebCamDevice.htmlnew 

In your Repro project you selecting last front facing device from a WebCamTexture.devices with an assumption that it will be correct one, but it is not valid with new Camera kind introduced.


・UnityのあるバージョンからiPhone/iPadのデプスカメラに対応したんだよ

・そんでそのぶんのカメラが増えてる

・現状のお前のアプリはfrontFacing かつ lastで選んでるから、Depthカメラを引いたんだよ


という回答だった。


いや、お前、それ、今まで一個しかなかったfront facing cameraを、isFrontFacingで検索してる今までのアプリ全滅するぞ、後方互換性破壊してるやんけ


と思ったが、ふーーーんなるほどー===~~~という感じで納得した。

納得いかないけど、旧来のアプリは大体死ぬが、破壊的変更ではあるが、


・front facing

・kind 

この2つを組み合わせてチェックする必要がある。


kind作るならカメラ一覧取得するときにGetDepthCameraとか作りなさいよという気持ちがMaxになりそうになるんだけど、

まーーーーーうーーーーーーーーーん、、、、ギリギリのギリギリで許す。


総評

互換性は破壊されている。俺は許すが俺の魂が赦すかな?!


wrote 2019/04/08 19:04:10

Quest用簡単モデリングツール Smowl 作る


概要

Mediumはもうあるんで、それのQuest版を作る。


モチベーション

VR上で以下がいい感じにやりたい。


・頂点系のモデリングしたい

・テクスチャをいい感じに描きたい

・ボーン入れたい

・モーションつけたい

wrote 2019/04/07 2:30:48

iOSで録音するときに音声出力ボリュームが下がるのの対策


概要

描いたまんま。

PlayAndRecord カテゴリを選ばないと、そもそも録音ができない。

が、この状態だと、端末から出力される音量が自動的にごく小さいものになってしまう。


それを解消する。


サンプルはObj-C。



こんなコードでいける

// なんらかカテゴリーを決めた後に、

[session setCategory:AVAudioSessionCategoryPlayAndRecord error:&err];


// オーディオルートの設定を書き換えれば、通常通りの音量で出力ができる。当然ハウり安いので注意。

UInt32 audioRouteOverride = kAudioSessionOverrideAudioRoute_Speaker;

AudioSessionSetProperty(kAudioSessionProperty_OverrideAudioRoute, sizeof(audioRouteOverride), &audioRouteOverride);




wrote 2019/03/13 3:34:37

ポータブルiOS/Androidアプリダウンロード機 ThreeFiveTwo


概要

とにかく無線でアプリを端末にインストールしたい。したくない? 有線でつなぐの辞めたいんだよね。ダルいし。UnityEditorから無線でダウンロードしたい。


Unity CloudBuildもいいんだけど、ちょっとDLして試したいだけで扱うのは面倒なんだよね。

主にメンテナンス的な意味で。


というわけで、ローカルでアプリをバラ撒けるような機構を仕立てようと思う。

名前に意味はない。352。鎖骨。




製作中。

wrote 2019/03/07 19:56:58

Androidのunity pluginDockerビルドする、CO2


概要

UnityのAndroid plugin作りにくいじゃない。

2018系使ってもうまくいかないケースとか踏むし。


なので、Dockerでビルドできるようにした。


そんなCO2

https://github.com/sassembla/CO2

正しいモチベーション

前提としてAndroidのlibraryをビルドするには、結構なサイズのソフトが必要。

特にAndroidStudioが捨てやすさという意味で最悪。


さらにgradleとかでビルドする際に、依存関係のDLとかに膨大な時間とディスクスペースを使う。本当にクソ。

なので、DockerでJavaとかの入れ物ごと作って捨てる。


これでよし。



使い方

1.モジュールプロジェクトをjavaとかkotlinとかで書いて、projectフォルダに放り込む

2.build.sh モジュール名 でビルド。


ね、簡単でしょう?

wrote 2019/02/25 0:51:10

Unityでインカメラを使ってストリーミング動画をアレする


概要

お前はなぜそれをUnityで シリーズ。

やる。



WebCamTexture

これ使えばいけそう。

https://docs.unity3d.com/ScriptReference/WebCamTexture-devices.html



ドキュメントに書いといてほしいんだけど、

Nativeのカメラから取得できるテクスチャ、無茶苦茶制約が強い。


具体的には、

・サイズ指定が効くわけではない、一番近いサイズが来る(なんでだよ)

・取得後にサイズ調整すると中身が消える(なんでだよ)

・Spriteにしてから取得しても中身が消える(いやだからなんでだよ)


なので、WebCamTexから取得 -> byte化 -> byteからテクスチャ生成 -> 変形 -> byte化 とかが使えるのでは。

-> いけた。


まとめ

WebCamTextureを使う場合、次のような手順を踏むといい感じにリサイズできる。


1.GetPixelsで通常のテクスチャに移動

2.このテクスチャをjpg byte[]に変換

3.jpeg byte[] からテクスチャを生成

4.3にリサイズ処理を施す

5.4をjpg byte[]に変換


ほんとなんでだよ。



まあ、ネイティブのUIImageとかが保持してるリソースのGetPixelsが、ポインタを移動してるだけなのでは?という気がしている。

wrote 2019/02/21 2:38:13

toriki日記


概要

UnityTwitter使うのだいたいC#コード90%でログインとかだけネイティブプラグインみたいなスタイルが固まってきたので、出す。



Why not TwitterKit(死んでるじゃん)

TwitterKitがDeadしてるのもあるんだけど、

そもそもTwitterKit iOS/Androidの実装がセッション保持してすごくバギーな挙動になるので、避けたくなった。

んで持続的にメンテ可能なUnity専用のTwitterログイン + API叩くツールを作るに至った。


これ

toriki

https://github.com/sassembla/toriki



インストール

リリースがあるのでそこからUnityPackageを使ってインストールできる。

https://github.com/sassembla/toriki/releases/tag/0.9.0




使い方


1.TwitterSetting.cs にconsumerKeyとかconsumerSecretを書く。


https://github.com/sassembla/toriki/blob/master/Assets/Toriki/Scripts/TwitterSettings.cs

        static TwitterSettings()

        {

            ConsumerKey = string.Empty;

            ConsumerSecret = string.Empty;

Runtimeにあるコードで、torikiの初期化を行う際に自動的にロードされる。

Resourcesとかにキーを暗号化しておいて、ここで復号化すると良い。



2.初期化とAPI


https://github.com/sassembla/toriki/blob/master/Assets/_Sample/Login/Login.cs

        TwitterAPI.InitWithLogin(

            (nickname, token, secret) =>

            {

                // show user info API example.

                TwitterAPI.Get(

                    "https://api.twitter.com/1.1/users/show.json",

                    new SortedDictionary<string, string>

                    {

                        {"screen_name", "toru_inoue"}

                    },

                    result =>

                    {

                        Debug.Log("show result:" + result);

                    },

                    (code, errors) =>

                    {

                        Debug.Log("show code:" + code);

                    }

                );


                // tweet API example.

                TwitterAPI.Post(

                    "https://api.twitter.com/1.1/statuses/update.json",

                    new SortedDictionary<string, string>

                    {

                        {"status", "Love Toriki. "}

                    },

                    result =>

                    {

                        Debug.Log("update result:" + result);

                    },

                    (code, errors) =>

                    {

                        Debug.Log("update code:" + code);

                    }

                );

            },

            (errorCode, message) =>

            {

                Debug.Log("login error:" + errorCode + " message:" + message);

            }

        );


Init、 Loginの順に実行する。


ログアウトはない。

(TwitterKitではアプリ側に通信セッションを保存したりしていたんだけどその辺が多大な問題を起こしていた上に、別にいらないのでいらない。 だから消した。)


APIは、TwitterAPI.Get/Postとか書いて、TwitterのAPI Referenceに書いてあるようなパラメータを入れれば使える。


3.APIだけを使う

Loginで得られるaccessToken、secretがあれば、ログイン処理をいちいち挟まずにAPIを使うことができる。


https://github.com/sassembla/toriki/blob/master/Assets/_Sample/APIAccess/APIAccess.cs

        TwitterAPI.InitWithToken("ACCESS_TOKEN", "ACCESS_SECRET");

        TwitterAPI.Get(

            "https://api.twitter.com/1.1/users/show.json",

            new SortedDictionary<string, string>

            {

                {"screen_name", "toru_inoue"}

            },

            result =>

            {

                Debug.Log("show result:" + result);

            },

            (code, errors) =>

            {

                Debug.Log("show code:" + code);

            }

        );


InitWithToken とか。以上。



wrote 2019/02/07 16:57:03

LWRP


概要

これに行った。

Unity道場 LWRP

https://meetup.unity3d.jp/jp/events/1034



特徴

以前よりは軽量、高速になった。


Upgradable Shaders(https://github.com/Unity-Technologies/ScriptableRenderPipeline/wiki/Lightweight-Render-Pipeline#upgradable-shaders) に対応表がある。


SRP(ScriptableRendererPipeline)で実装されているため、カスタムシェーダでの面白表現とかがやりやすくなっている。



最近のバッチング

1マテリアルにつき、コンスタントバッファ作成 -> アップ -> 描画

ダイナミックバッチングでマテリアルごとにオブジェクトを結合、、!ってやってたんだけど、

ポリゴンが増えてきたんでバッチングはオフな方が効率が良くなってきた。

-> 代わりにInstancingを使おう。


SRPでは

UnityPerMaterial という属性で要素をUnityに登録する必要がある(キーワード)

するとSRPBatchingが発生する。



SRP勉強せんとな。

IRenderSetupを継承で云々とか。



俺はUVスクロールがしたかっただけなんだ

作っていくうちにガンガン高まっていく人見てると良い良いって感じになってくる

wrote 2019/01/30 19:09:49

Tiny Mode触ってみる


概要

ここを参考に触る

https://qiita.com/tkyaji/items/be7db0b419ce27c2a184



パッケージインストール

Window > Package Manager > Advancedボタンをクリックしてpreviewを選択 > previewを検索してインストール


インストールが完了するまで待つ。完了するとTinyメニューがでる。



サンプルプロジェクトの収集

Tiny > Import Samples でサンプルを収集、TinySamples/*/*.utproject ファイルを開いてPlay実行すると、ブラウザが開いてゲームが遊べる。



ログ

typescript内で普通にconsole.logが使える。これUnityEditorに返せると見やすいか? そうでもないか。

今の所はTSなので、何か知りたいことがあったらログを書く -> ブラウザで実行



TinyでのEntityとは

Assetsウィンドウがこんな感じ。

スクリーンショット 2019-01-13 13.46.26.png


エンティティの縛りをもってシーンの扱いとしてるっぽい。

起動時はBootstrapのシーンになっている。



基本動作

ComponentSystemというクラスと、OnUpdate : void みたいな関数があって、

その関数内でthis.world.forEach([エンティティ定義 x n]){

エンティティの調整

}

とやることで、エンティティの動作をいい感じにできる。



作って見たいもの

ミニゲーム、マリオみたいなやつ。












wrote 2019/01/13 11:30:15

ECSのまなび


概要

まなぶ。参考は凹みさんのやつ。


「Unity で Boids シミュレーションを作成して Entity Component System(ECS)を学んでみた」

http://tips.hecomi.com/entry/2018/12/23/200817



BoidSimulation

他のすべてのBoidの位置を見たりして動くBoidと、

それらを生成するSimulationという組み合わせ。


ここから、ECSに向けて分解していく。



entityを導入

パッケージマネージャーから導入。



BoidECS対応

Boid、中では

・加速度、位置などのパラメータがある

・関数でそれらの中に値をセットする

ということをやっていて、


これを、

パラメータ -> エンティティ化

関数 -> システム化


ということをやっていく。


動きのバリエーションとしては、

・壁に近づいたら云々

・向きとか速度を云々

・他の個体と近づく離れるを云々

する。


パラメータの分解粒度については、

・各種システムが必要な情報をグルーピングしてくるときに本当に必要な最小の粒度で分解した方が良い

ということなので、


まずは最小粒度でエンティティ化してみよう。


コンポーネントの作成

コンポーネント = ECSで扱う型情報の定義、みたいな印象。

IComponentDataを継承したstructを定義し、内部にUnity.Mathematics に定義されている型(float3とか)を保持する。

float3は、3つのfloatが入っている型。


起動クラスの作成

ECSの関連性を起動する()ような処理を書く。

・コンポーネントの定義

・デフォルトのWorldからEntityManagerを取得

・アーキタイプと呼ばれるものをmanagerにセット

・レンダラの生成

・エンティティの生成、コンポーネントの追加



コンポーネントの定義

public struct Velocity : IComponentData

{

    public float3 Value;

}


public struct Acceleration : IComponentData

{

    public float3 Value;

}

IComponentDataを継承した型を生成しておく。

この型をエンティティにセットすることで、エンティティに対して任意の値を持たせることができるようになる。



デフォルトのWorldからEntityManagerを取得

Worldは自分で生成することもできる。

var manager = World.Active.GetOrCreateManager<EntityManager>();


このmanagerに対して、レンダラやアーキタイプをセットしていく。



アーキタイプと呼ばれるものをmanagerにセット

var archetype = manager.CreateArchetype(

            typeof(Position),

            typeof(Rotation),

            typeof(Scale),

            typeof(Velocity),

            typeof(Acceleration),

            typeof(MeshInstanceRenderer));


managerに対して、用意したComponentをセットしてく。


Position、Rotation、Scale、MeshInstanceRendererはUnityが用意してくれているものを使用、

Velocity、Accelerationはさっき書いたものをセットする。


こうすることで、archetypeを生成できる。

archetypeはComponentの型を列挙したデータを含んでいるインスタンス。



レンダラの生成

        var renderer = new MeshInstanceRenderer

        {

            castShadows = ShadowCastingMode.On,

            receiveShadows = true,

            mesh = mesh,

            material = material

        };

エンティティに対して描画時に使用する機構を生成しておく。

このrendererはあとでエンティティを生成する時にセットする。



エンティティの生成、コンポーネントの追加

            var entity = manager.CreateEntity(archetype);

            manager.SetComponentData(entity, new Position { Value = random.NextFloat3(1f) });

            manager.SetComponentData(entity, new Rotation { Value = quaternion.identity });

            manager.SetComponentData(entity, new Scale { Value = new float3(boidScale.x, boidScale.y, boidScale.z) });

            manager.SetComponentData(entity, new Velocity { Value = random.NextFloat3Direction() * param.initSpeed });

            manager.SetComponentData(entity, new Acceleration { Value = float3.zero });

            manager.SetSharedComponentData(entity, renderer);

managerに対して、archetypeを渡すことでエンティティを生成する。


こうすることで、これらのコンポーネントを持ったEntityが生成される。

で、entityのそれぞれのコンポーネントに対してデータをセットすることができる。

最終的にentityに対してrendererをセットすると完了で、動き出す。


ここまでで、エンティティの生成は完了。

次に、これらのエンティティを動かす仕掛け(System)について考える。



エンティティを動かす

ComponentSystemを生成する。

・データ型をどこかに定義(外部でもいいはず)

・ComponentSystem型を継承した型を生成、データ型をクラス内のフィールドにインジェクト

・OnUpdate関数を書く



データ型をどこかに定義(外部でもいいはず)

こんな感じの型を作る。

    struct Data

    {

        public readonly int Length;

        public ComponentDataArray<Position> positions;

        [WriteOnly] public ComponentDataArray<Rotation> rotations;

        public ComponentDataArray<Velocity> velocities;

        public ComponentDataArray<Acceleration> accelerations;

    }

Lengthには、自動的に「何個のEntityがあるか」が入る。つまりこの数分だけエンティティがある、という情報を取得できる。

positionとかがarrayになっていて、「すべてのエンティティのpositon」が入っているアレイになっている。すごい。



ComponentSystem型を継承した型を生成、データ型をクラス内のフィールドにインジェクト


public class WallSystem : ComponentSystem

{

    struct Data

    {

        public readonly int Length;

        [ReadOnly] public ComponentDataArray<Position> positions;

        public ComponentDataArray<Acceleration> accelerations;

    }


    [Inject] Data data;


    protected override void OnUpdate()

    {

.....


        for (int i = 0; i < data.Length; ++i)

        {

            data.accelerations[i] = new Acceleration { Value = accel };

        }

    }

}


OnUpdateが毎フレーム実行される。

Data型をInjectアトリビュートをつけて定義しているが、このインスタンスに対して自動的にエンティティが入る。


で、MoveとWallをセットすることで、移動と壁接近の処理を実現できる。

これらのComponentSystemを継承した型は、自動的にデフォルトのWorldに組み込まれる。


ここまでで壁接近と移動に関してのシステムができた。


で、その実行順の制御をいまのところはMoveSystemにattributeで

[UpdateAfter(typeof(WallSystem))]

とかやって行う。


ここからは、一つのエンティティから別のエンティティを参照して、群(Boid)っぽい挙動をさせる。

他の個体と近づく離れるを云々 の部分。


この場合、一つのエンティティから、ほかの(近所の)エンティティを、配列として扱うことになる。



配列をエンティティ内で扱う

データ型を定義する。

[InternalBufferCapacity(8)]

public struct NeighborsEntityBuffer : IBufferElementData

{

    public Entity Value;

}

IBufferElementDataを継承したコンポーネントを用意する。これで配列が扱える。

今まではIComponentData。


Entityを値として持つ。(配列として扱われる。)


アトリビュート InternalBufferCapacity はIBufferElementDataに対してセットする。

この数値を超えた場合はデータがC#のヒープにいってしまって遅くなるっぽい。


アーキタイプにNeighborsEntityBuffer型を足す。


        var archetype = manager.CreateArchetype(

            typeof(Position),

            typeof(Rotation),

            typeof(Scale),

            typeof(Velocity),

            typeof(Acceleration),

            typeof(MeshInstanceRenderer),

            typeof(NeighborsEntityBuffer)

        );

NeighborsEntityBuffer 型に関しては、CreateEntity時にデータをセットするような要素がないのでこのまま。


IBufferElementDataを継承した型の中身は、自動的に配列として扱われる。

この場合は、Entity型のアレイになる。


Bufferからデータを取り出す場合、Reinterpret<バッファに含まれている型> で、型のアレイが取り出せる。


            /*

                neighborsから一つを取り出す。ここでNeighborsEntityBufferの中身はEntityだけなので、

                Reinterpret<>で指定するとEntityのアレイが手に入る。

            */

            var neighbors = data.neighbors[i].Reinterpret<Entity>();

これで、neighborsは DynamicBuffer<Entity> 型、Entityのアレイになる。

で、エンティティからPositionなどの一パラメータを取得するには、 EntityManager.GetComponentData<Position>(対象のエンティティ) とかやる。


このほかにAlignment(整列)とCohesion(結束)のSystemを作る。



順番付け

この時点で複数のシステムがあって、順番問題が出てくる。

別に複数のシステムに分けなくてもいいはずなんで、まとめてもいいんだけど、ここでは

・特定のまとまり

・その前

・そのあと

というような区分けで順番付けを行うことができる。


[UpdateInGroup(typeof(クラス))]


とかで、特定のクラス定義を基にしたグループを生成できる。

このグループ内だとなんかどういう順番での実行になるかわからないが、


[UpdateAfter(typeof(クラス))]

とかやると、グループの実行後に実行、

[UpdateBefore(typeof(クラス))]

でグループの実行前に実行、とかができる。

グループが生成できるのがいいところ。



ECSといってもメインスレッドで動くのがデフォルトなんだな~

というわけで、ここからは別スレッドでの実行にしていく。

WallSystemのベースクラスを ComponentSystem から JobComponentSystem に載せ替えて、OnUpdateがJobHandleを返すようにセットする。


    public struct Job : IJobParallelFor

    {

        // OnUpdate() から渡してもらう

        [ReadOnly] public ComponentDataArray<Position> positions;


        [ReadOnly] public float scale;

        [ReadOnly] public float thresh;

        [ReadOnly] public float weight;


        public ComponentDataArray<Acceleration> accelerations;

        // [ReadOnly] public Param param;


        // OnUpdate() の処理を移植

        public void Execute(int index)

        {

            float3 pos = positions[index].Value;

            float3 accel = accelerations[index].Value;

            accel +=

                GetAccelAgainstWall(-scale - pos.x, new float3(+1, 0, 0), thresh, weight) +

                GetAccelAgainstWall(-scale - pos.y, new float3(0, +1, 0), thresh, weight) +

                GetAccelAgainstWall(-scale - pos.z, new float3(0, 0, +1), thresh, weight) +

                GetAccelAgainstWall(+scale - pos.x, new float3(-1, 0, 0), thresh, weight) +

                GetAccelAgainstWall(+scale - pos.y, new float3(0, -1, 0), thresh, weight) +

                GetAccelAgainstWall(+scale - pos.z, new float3(0, 0, -1), thresh, weight);

            accelerations[index] = new Acceleration { Value = accel };

        }


        float3 GetAccelAgainstWall(float dist, float3 dir, float thresh, float weight)

        {

            if (dist < thresh)

            {

                return dir * (weight / math.abs(dist / thresh));

            }

            return float3.zero;

        }

    }

JobSystemを使って並列化(メインスレッド以外での実行)するために、IJobParallelFor型を継承したstructを用意する。

Execute関数の中で、Updateで実行していた要素を実行する。


Execute関数はエンティティ分だけ実行される。



    protected override JobHandle OnUpdate(JobHandle inputDeps)

    {

        var job = new Job

        {

            positions = data.positions,

            accelerations = data.accelerations,


            // IJobParallelForを継承したstructは参照型の参照を持てないので、ここで値を渡す。

            scale = Bootstrap.Param.wallScale * 0.5f,

            thresh = Bootstrap.Param.wallDistance,

            weight = Bootstrap.Param.wallWeight

        };

        return job.Schedule(data.Length, 32, inputDeps);

    }

これで、WallSystemでのOnUpdate -> Job、という形でデータが別スレッドで処理されるようになる。

素敵。


もっとECSに向いたJob関連の仕組みがあるので、そちらを使って全体を移行する。



IJobProcessComponentData型を使ってジョブ化を行う

IJobProcessComponentData

型を使ってジョブの定義を行うと、引数を持たせた上でExecuteの定義ができる。

次のように型引数をセットして定義、

    private struct Job : IJobProcessComponentData<Position, Rotation, Velocity, Acceleration>

    {

        [ReadOnly] public float dt;

        [ReadOnly] public float minSpeed;

        [ReadOnly] public float maxSpeed;


        public void Execute(ref Position pos, [WriteOnly] ref Rotation rot, ref Velocity vel, ref Acceleration accel)

        {

            var v = vel.Value;

            v += accel.Value * dt;

            var dir = math.normalize(v);

            var speed = math.length(v);

            v = math.clamp(speed, minSpeed, maxSpeed) * dir;


            pos = new Position { Value = pos.Value + v * dt };

            rot = new Rotation { Value = quaternion.LookRotationSafe(dir, new float3(0, 1, 0)) };

            vel = new Velocity { Value = v };

            accel = new Acceleration { Value = float3.zero };

        }

    }

Executeはやはりエンティティ数分だけ実行される。

jobを返すのを要求している JobComponentSystem のOnUpdateで、パラメータを含んだjobを生成し、Scheduleを返す。


    protected override JobHandle OnUpdate(JobHandle inputDeps)

    {

        var job = new Job

        {

            dt = Time.deltaTime,

            minSpeed = Bootstrap.Param.minSpeed,

            maxSpeed = Bootstrap.Param.maxSpeed,

        };

        return job.Schedule(this, inputDeps);

    }

Execute関数にはPositionやら何やらが型定義時点の要素で入ってくるので、パラメータの特性をAttributeでセットする。

この場合はRotationがWriteしかしないので、WriteOnlyにする。


このExecute関数で渡ってくるrefは、Injectしていた時の要素と同じような感じ。


OnUpdate関数がメインスレッドで、そこからJobSystemへとジョブを送り出す。

JobSystem側では別スレッド(WorkerThread)経由でExecuteが呼ばれ、そこで処理を行う。



配列を扱う(特にEntityの配列)

SeparationSysytemをJob化する。


neighborsがEntityのアレイなので、その辺を扱う必要がある。

IJobProcessComponentDataWithEntity

型でjob用のデータを定義すると、Executeの第一引数にEntity型、第二引数にint indexがつく。

それ以降の引数は定義型と一致する。


public void Execute(Entity entity, int index, [ReadOnly] ref Position pos, ref Acceleration accel){


こんな感じ。


OnUpdateではjobを生成してスケジュールを返すんだが、

    protected override JobHandle OnUpdate(JobHandle inputDeps)

    {

        // パラメータをつけてJobSystemに放り込む

        var job = new Job

        {

            separationWeight = Bootstrap.Param.separationWeight,


            /*

                JobComponentSystem GetBufferFromEntity メソッドを持っているので、

                NeighborsEntityBufferの型指定でエンティティからバッファを取り出す。

                エンティティをキーにしたNeighborsの一覧という形で、ジョブの実行先で取り出すのを予定する。         

            */

            neighborsFromEntity = GetBufferFromEntity<NeighborsEntityBuffer>(true),


            /*

                Position型指定でエンティティからコンポーネントを取り出す。

                エンティティをキーにしたポジションの一覧という形で、ジョブの実行先で取り出すのを予定する。

             */

            positionFromEntity = GetComponentDataFromEntity<Position>(true),

        };

        return job.Schedule(this, inputDeps);

    }


IJobProcessComponentDataWithEntity を継承したstruct側では、そのExecuteでentityを含んだ実行ブロックになる。


    public struct Job : IJobProcessComponentDataWithEntity<Position, Acceleration>

    {

        [ReadOnly] public float separationWeight;

        [ReadOnly] public BufferFromEntity<NeighborsEntityBuffer> neighborsFromEntity;

        [ReadOnly] public ComponentDataFromEntity<Position> positionFromEntity;


        public void Execute(Entity entity, int index, [ReadOnly] ref Position pos, ref Acceleration accel)

        {

            var neighbors = neighborsFromEntity[entity].Reinterpret<Entity>();


            if (neighbors.Length == 0)

            {

                return;

            }


            var pos0 = pos.Value;


            var force = float3.zero;

            for (int i = 0; i < neighbors.Length; ++i)

            {

                var pos1 = positionFromEntity[neighbors[i]].Value;

                force += math.normalize(pos0 - pos1);

            }

            force /= neighbors.Length;


            var dAccel = force * separationWeight;

            accel = new Acceleration { Value = accel.Value + dAccel };

        }

    }


で、neighborsFromEntity は辞書みたいな形になっていて、

エンティティ分だけ実行されるExecuteに対して、entityをキーとしてneighborsのバッファを取得することができる。


同じくpositionもエンティティをキーとした辞書にしてあって、取得できる。

最終的に、accelの値を更新して終了。


最後に、NeighborDetectionSystemをJob化する。



NeighborDetectionSystemをJob化

IJobProcessComponentDataWithEntity を使ってJobの定義を行う。


で、NeighborDetectionSystemについては、

・エンティティの近所にあるエンティティを集める

という必要性があるため、収集のための機構を作る必要がある。


    ComponentGroup group;


    protected override void OnCreateManager()

    {

        /*

            ComponentSystemBaseに生えてるメソッド GetComponentGroup で、特定のエンティティを集める。

         */

        group = GetComponentGroup(

            typeof(Position),

            typeof(Velocity),

            typeof(NeighborsEntityBuffer));

    }



ComponentSystemBase にあるGetComponentGroupメソッドで、

グループという単位を作り Position、Velocity、NeighborsEntitiyBuffer コンポーネントをくくり出せるようにしている。


group.GetEntityArray()


で、Position、Velocity、NeighborsEntitiyBuffer コンポーネントを持ったエンティティを収集できる。


    protected override JobHandle OnUpdate(JobHandle inputDeps)

    {

        var job = new Job

        {

            prodThresh = math.cos(math.radians(Bootstrap.Param.neighborFov)),

            distThresh = Bootstrap.Param.neighborDistance,

            neighborsFromEntity = GetBufferFromEntity<NeighborsEntityBuffer>(false),

            positionFromEntity = GetComponentDataFromEntity<Position>(true),

            entities = group.GetEntityArray(),

        };

        return job.Schedule(this, inputDeps);

    }


jobを生成。entitiesパラメータに取得したエンティティを入れる。

jobの定義は次のような感じで、EntityArray entitiesにgroupから取得したエンティティが入る。


    public struct Job : IJobProcessComponentDataWithEntity<Position, Velocity>

    {

        [ReadOnly] public float prodThresh;

        [ReadOnly] public float distThresh;

        [ReadOnly] public ComponentDataFromEntity<Position> positionFromEntity;

        [ReadOnly] public BufferFromEntity<NeighborsEntityBuffer> neighborsFromEntity;

        [ReadOnly] public EntityArray entities;


        public void Execute(

            Entity entity,

            int index,

            [ReadOnly] ref Position pos,

            [ReadOnly] ref Velocity velocity)

        {

            neighborsFromEntity[entity].Clear();


            float3 pos0 = pos.Value;

            float3 fwd0 = math.normalize(velocity.Value);


            for (int i = 0; i < entities.Length; ++i)

            {

                var neighbor = entities[i];

                if (neighbor == entity) continue;


                float3 pos1 = positionFromEntity[neighbor].Value;

                var to = pos1 - pos0;

                var dist = math.length(to);


                if (dist < distThresh)

                {

                    var dir = math.normalize(to);

                    var prod = Vector3.Dot(dir, fwd0);

                    if (prod > prodThresh)

                    {

                        neighborsFromEntity[entity].Add(new NeighborsEntityBuffer { Value = neighbor });

                    }

                }

            }

        }

    }


Executeごとにentitiesの中身を捜査して近いエンティティを見つけ、

自身のneighborsに入れる。


という感じで、収集ができる。



ここまでのまとめ

コンポーネント(ECSで扱うデータ型)の定義

IComponentData型を継承して、型を定義する。(Unityが定義済みの型があり、それ以外にも定義できる)


IBufferElementData型を継承して、扱う配列を定義する。

InternalBufferCapacityアトリビュートでをセットする。


エンティティの生成

ワールド、エンティティマネージャーを生成


アーキタイプ(エンティティに対してくっつけるコンポーネントの集合)を定義


マネージャ経由でアーキタイプからエンティティ生成



ECS2パターン


パターン1、ComponentSystem型を継承したシステムを定義、Injectしたデータを void OnUpdate で変形したりする(メインスレッド、ちょっとは高速)

この場合、定義したシステムに対してコンポーネントの定義を別途Injectすると、そのフィールドに対してOnUpdateのタイミングでエンティティが入り、変更を加えることができるようになる。

変更すると、エンティティにも値が反映される。



パターン2、JobComponentSystem型を継承したシステムを定義、次のどれかの型の継承でJobを定義、JobHandle OnUpdate(JobHandle handle)  でJob作成

-> 投入、Job側のExecuteで(workerスレッド、高速)


IJobParallelFor Execute(int index)

IJobProcessComponentData<T(, ~ T3) Execute(ref T t)

IJobProcessComponentDataWithEntity<T(, ~ T3)> Execute(Entity entity, int index, ref T t)



T1~3にはReadOnlyなどのアトリビュートをつけることで、アクセスの最適化を行う。


JobはBurstCompiler対応でめっちゃ高速化される。


値に対して、Job内でパラメータを編集するという形で値の反映を行う。


双方とも、OnUpdateメソッドはメインスレッドで1フレームに一回実行される。

Jobがメインスレッドからしか放り込めないのに起因してる。



JobのExecuteはヒットしたエンティティの数ぶん実行される。

IJobProcessComponentData<T>などのTに該当するエンティティ全てが対象になる。

Tは扱いたいデータ自体の選出のほか、フィルタリングにも使っている。


特殊な型ペイロード


ComponentDataFromEntity<T>

entityをキーに、値として T を取り出すことができる辞書。

ComponentSysytem型が保持しているGetComponentDataFromEntity<T>(bool isReadOnly) メソッドで取得できる。

ここで取得できるのは、その時のWorldに存在するT型のエンティティを収集した辞書。



BufferFromEntity<T>

entityをキーに、値として DynamicBuffer<T> を取り出すことができる辞書。

JobComponentSystem型が保持しているGetBufferFromEntity<T>(bool isReadOnly) メソッドで取得できる。

ここで取得できるのは、その時のWorldに存在するT型のエンティティを収集した辞書。


DynamicBuffer<T>

BufferFromEntity<T>型から、Reinterpret<S> (SはTに含まれている型)とかで、DynamicBuffer<S> を取り出せる。



Jobの制約

Jobの内部では、エンティティ収集などができない。

収集処理とかはメインスレッド = ComponentSystemのOnUpdateとか で行う必要がある。


ComponentSystem/OnUpdateは、参照とかをJobに放り込む地点になる。



ざっくり書くとどういうことをやっているか

・コンポーネント型を定義(バッファとかデータとか)

・コンポーネントを保持したエンティティ生成

・システムを定義して、特定のコンポーネントを持つエンティティを収集、OnUpdateでデータをいじったり、データをいじるJobを作り、JobSystemに投入、実行

こんだけ。

コンポーネントの型をキーにWorldに散らばっているエンティティを収集して、JobSystem上で値を変えることで描画に影響を与える。



別のSystemにわけて書いてあるものをまとめる

複数のJobをそれぞれ1つのSystemに別れて定義しているが、特にわかりやすい以外の利点はない。

で、これらをまとめて一つのSystemに定義することができる。


そうすることで、システム間の待ちを根本的に減らせる。


    protected override JobHandle OnUpdate(JobHandle inputDeps)

    {

        /*

            近いエンティティの収集

         */

        var neighbors = new NeighborsDetectionJob

        {

            prodThresh = math.cos(math.radians(Bootstrap.Param.neighborFov)),

            distThresh = Bootstrap.Param.neighborDistance,

            neighborsFromEntity = GetBufferFromEntity<NeighborsEntityBuffer>(false),

            positionFromEntity = GetComponentDataFromEntity<Position>(true),

            entities = group.GetEntityArray(),

        };


        /*

            壁処理

         */

        var wall = new WallJob

        {

            scale = Bootstrap.Param.wallScale * 0.5f,

            thresh = Bootstrap.Param.wallDistance,

            weight = Bootstrap.Param.wallWeight,

        };


        /*

            近所のエンティティから離れる

         */

        var separation = new SeparationJob

        {

            separationWeight = Bootstrap.Param.separationWeight,


            /*

                JobComponentSystem GetBufferFromEntity メソッドを持っているので、

                NeighborsEntityBufferの型指定でエンティティからバッファを取り出す。

                エンティティをキーにしたNeighborsの一覧という形で、ジョブの実行先で取り出すのを予定する。         

            */

            neighborsFromEntity = GetBufferFromEntity<NeighborsEntityBuffer>(true),


            /*

                Position型指定でエンティティからコンポーネントを取り出す。

                エンティティをキーにしたポジションの一覧という形で、ジョブの実行先で取り出すのを予定する。

             */

            positionFromEntity = GetComponentDataFromEntity<Position>(true),

        };


        /*

            均整化

         */

        var alignment = new AlignmentJob

        {

            alignmentWeight = Bootstrap.Param.alignmentWeight,

            neighborsFromEntity = GetBufferFromEntity<NeighborsEntityBuffer>(true),

            velocityFromEntity = GetComponentDataFromEntity<Velocity>(true),

        };


        /*

            距離調整

         */

        var cohesion = new CohesionJob

        {

            cohesionWeight = Bootstrap.Param.cohesionWeight,

            neighborsFromEntity = GetBufferFromEntity<NeighborsEntityBuffer>(true),

            positionFromEntity = GetComponentDataFromEntity<Position>(true),

        };


        /*

            移動

         */

        var move = new MoveJob

        {

            dt = Time.deltaTime,

            minSpeed = Bootstrap.Param.minSpeed,

            maxSpeed = Bootstrap.Param.maxSpeed,

        };


        // 順番に動作を行うように、ジョブを連結してスケジューリングする。

        inputDeps = neighbors.Schedule(this, inputDeps);

        inputDeps = wall.Schedule(this, inputDeps);

        inputDeps = separation.Schedule(this, inputDeps);

        inputDeps = alignment.Schedule(this, inputDeps);

        inputDeps = cohesion.Schedule(this, inputDeps);

        inputDeps = move.Schedule(this, inputDeps);


        // 最終的なJobHandleを返す。

        return inputDeps;

    }


JobComponentSystemのOnUpdate関数でそれぞれのJobの初期化をし、Scheduleメソッドでチェーンしまくる。

連結してSchedulingすることができる。



JobをBurstCompileで高速化

BurstCompileアトリビュートをJob定義につける。そんだけで高速化。




wrote 2018/12/26 17:35:57

AutoyaにURLSchemeハンドリング機構を追加した。


概要

AndroidでもURLSchemeからの起動とかでなんかパラメータ扱いたいよねみたいな話を叶えた。



iOSと違って特に面倒臭いところ

iOSの場合、コードやプロジェクト側に特定のスキーマを入れる必要はなく、Xcodeの設定をいじるコードが一節あればいいのだが、

Androidの場合はAndroidManifest.xmlに対してスキーマを書く必要がある。


その際、まあ、よくあると思うんだけど、AndroidManifestのマージ問題に遭遇することになる。


メインのAndroidManifestはAssets/Plugins/Androidに置くとして、サブのいろんな機能のAndroidManifest.xmlは別のところに置き、Unityにマージしてもらう。

で、[AndroidManifestがマージされる]ための条件は以下の通り。



AndroidManifest.xmlがマージされるための条件


1.Assets/Plugins/Android/FOLDER_NAME/以下にAndroidManifest.xmlを置く

これより深くても浅くてもダメ。


2.project.propertiesというファイルをAndroidManifest.xmlと同じフォルダに置く。

中身は、

target=android-16

android.library=true


とか。


3.manifestの内容は以下のような感じでOK

<manifest

    xmlns:android="http://schemas.android.com/apk/res/android"

    package="com.unity3d.player"

    xmlns:tools="http://schemas.android.com/tools"

    android:versionCode="1"

    android:versionName="1.0">

    <application>

        <activity ....

        </activity>

    </application>

</manifest>


本体となるAndroidManifest.xmlに必要な、<?xml version="1.0" encoding="utf-8"?> とかのxmlの定義は不要。

manifestの中のアトリビュートは必須。


ということで、XMLのマージ問題はこれで解決できる。


project.propertiesがないとマージされなかったんだけど、これってなんなんだろう。


ドキュメントには特に書いてなかったが、github上のいろいろを眺めていて、project.propertiesファイルを適当に作ったら合成された。

wrote 2018/12/20 19:51:31

Autoyaのlink.xml Generator作った回


概要

Autoya 0.9.5のリリースが完了した。

このリリースでは、わりと「ずっと前から欲しかったんだけど入れられなかった機能」みたいなのを入れた。


・link.xml を生成する機構

・AssetGraphでAssetBundleをビルドした時についでにlink.xmlを合成出力する機構

・こまかなバグフィックス


などが更新内容。


このなかで、AssetGraph -> AB作成 -> link.xml生成が熱い。



AssetBundleとアプリ内含有Assetの関係

iOSとかAndroidでのAssetBundleの使用がマストなので、こう、

「そのABに入ってるAssetはコンパイルに含まれてないのでロードした瞬間、死!!!」

みたいなのが怖い。


そこでいろいろな方法があるわけなんだけど、


Autoyaでは、link.xmlを生成することで対処した。


link.xml Generator

AssetのクラスID値(int)を与えるとlink.xmlを吐き出す。

これ。

https://github.com/sassembla/Autoya/blob/master/Assets/Editor/Autoya.AssetGraphIntegration/LinkXMLGenerator.cs#L60


単体で抜き出しても使えるので、興味ある人はどうぞ。



で、ここで渡すクラスID値とは何か。

間違ってもここのこれではない

https://docs.unity3d.com/Manual/ClassIDReference.html

この資料ほんんんんんんっっっっっっっっっとーに最悪なことに、間違いまくっている。


なので、クラスID値を知りたい人は、


とりあえずAssetBundleをビルドしてmanifestファイルを見よう。

こんな感じのやつが出てくる。

https://github.com/sassembla/Autoya/blob/master/AssetBundles/main_assets/iOS/nestedprefab.manifest#L12


ManifestFileVersion: 0

CRC: 2200902407

Hashes:

  AssetFileHash:

    serializedVersion: 2

    Hash: c088a4b2797e99ed3c95d8ce957816af

  TypeTreeHash:

    serializedVersion: 2

    Hash: 11817dad4d3c8e9c24248d58700284ea

HashAppended: 0

ClassTypes:

- Class: 1

  Script: {instanceID: 0}

- Class: 4

  Script: {instanceID: 0}

- Class: 23

  Script: {instanceID: 0}

- Class: 102

  Script: {instanceID: 0}

- Class: 114

  Script: {fileID: 11500000, guid: 7e73406419bf54a50a1b5faf24749c6c, type: 3}

- Class: 115

  Script: {instanceID: 0}

Assets:

- Assets/AutoyaTests/RuntimeData/AssetBundles/MainResources/nestedPrefab.prefab

Dependencies:

- /Users/passepied/Desktop/autoya/Editor/AssetGraph-1.3-release/UnityEngine.AssetBundleGraph/Cache/AssetBundles/4e024a18-af2d-4f29-9f4b-1212e005d1ea/iOS/texturename1


ここの、Class: 1 とかが、「そのABに含まれているAssetの」「Unity内での」クラスIDの値になっている。

ほらね、簡単でしょう?



この数値はmetaファイルとかからは取得できない。できたら別のアプローチとかもあると思うんだけど。



現状のまとめ

Autoyaでは、AssetBundleを作成する際にAssetGraphを使っており、AGのビルド時に独自のAssetBundleListを作る機構を提供している。


で、


List作成のついでに、ビルドしたAssetBundleのmanifestから、ABに含まれる全てのAssetのクラスIDを収集し、

そのIDをもとにlink.xmlを生成している。


すでにファイルがある場合は必要な分をマージする。

これによって、複数のAGのグラフからABをビルドしても一つのlink.xmlがいい感じに太っていくようになる。






wrote 2018/12/17 22:52:29

SHOWROOM x IRIAM イベントいってきた


概要

これ

「Vtuberサービス開発の裏側チラ見せします - VR Tech Night#1」

https://iriam.connpass.com/event/110072/



IRIAMで自分が担当してたのは配信サーバまわりとクライアント。

そのへんの悲喜こもごもを死霊にした。



死霊(資料ではない)


IRIAMを斜め45度から支える技術

https://speakerdeck.com/sassembla/e2



なぜ発表死霊の名前がe2なのか!?

、、、、そこには実は配信機構との隠された繋がりが存在しない。



感想

まだ正気保ってる。




wrote 2018/12/13 15:43:20

JobSystemまなび


概要

学ぶ。

面倒臭い人は最後だけ見ると良い。



途中経過

こんな感じのコードにしてみる


using System;

using System.Collections;

using System.Collections.Generic;

using Unity.Collections;

using UnityEngine;


public class JS : MonoBehaviour

{

    [SerializeField] Transform[] targets;

    float[] velocity;


    // Start is called before the first frame update

    void Start()

    {

        velocity = new float[targets.Length];

    }


    // Update is called once per frame

    void Update()

    {


        var commands = new NativeArray<RaycastCommand>(targets.Length, Allocator.TempJob);

        var results = new NativeArray<RaycastHit>(targets.Length, Allocator.TempJob);


        for (var i = 0; i < targets.Length; i++)

        {

            var targetPosition = targets[i].position;

            var direction = Vector3.down;


            // 指定位置から下方向にレイキャストを行うコマンドをまとめる

            // RaycastCommand型は、結果にReycastHit型を返してくる。

            var command = new RaycastCommand(targetPosition, direction);

            commands[i] = command;

        }


        /*

            コマンドを実行、結果はresultsに入る。


            RaycastCommandで入力したコマンドは、RaycastHitを返してくる。

            (これはraycastCommand型のScheduleBatch関数がそういう実装になってる)

         */

        // 完了まで待つ(ここでデッドロックしないのはなぜなんだろう、継続になってる? それともそういうのを加味しないでいいくらい高速?)

        // -> 待ってる。十分に高速なら問題ないというロジック。

        // 最後の引数はjobの最大分散数。

        var commandJobHandle = RaycastCommand.ScheduleBatch(commands, results, 10);


        // jobHandleの終了を待つ

        commandJobHandle.Complete();


        // 破棄

        commands.Dispose();


        // 加速度をセット、速度がマイナス(下に移動)、かつレイキャストの距離が一定以下だったらぶつかったとみなす。

        for (var i = 0; i < targets.Length; i++)

        {

            if (velocity[i] > 0 && results[i].distance < 0.5f)

            {

                velocity[i] = -2;

            }


            velocity[i] += 0.098f;

        }

        results.Dispose();


        // 加速度分移動

        for (var i = 0; i < targets.Length; i++)

        {

            targets[i].localPosition += Vector3.down * velocity[i];

        }

    }

}

前提として、targets配列にはエディタ上でcubeオブジェクトをセットしておく。

あと、ヒット対象となる地面(Terrainとか)を用意しとく。


結果

いい感じにMainと他3スレッド(マシンが4コアなので合計4)で分散できた。

これワーカー数はコア数と一致するんだろうか、、


スクリーンショット 2019-01-05 22.33.15.png


アップで見るとこんな感じで、

・どれか一つのスレッドがResultJobを実行

・メインスレッドのWaitForJobGroupIDがそれを受ける

みたいな感じに見える。

スクリーンショット 2019-01-05 22.40.06.png


ここまでで、Raycastを打つ部分はJob化できてる。で、次に

・ヒットチェックして加速度を 制御する部分

・移動させる部分

をJob化してみる。


この時点で100fps前後。



ヒットチェック部分のJob化


グローバルに定義してあるvelocityはNativeArray<float>にしておく。

このあとJobからアクセスする要素を生成する時に代入するため。

    NativeArray<float> velocity;

んで、このインスタンスはOnEnableで生成、OnDisableで削除するようにする。


    void OnEnable()

    {

        velocity = new NativeArray<float>(targets.Length, Allocator.Persistent);

        for (int i = 0; i < targets.Length; i++)

        {

            velocity[i] = 1;

        }

    }


    void OnDisable()

    {

        velocity.Dispose();

    }



そんでまずHitCheckJobを、IJobParallelFor structを拡張する形で定義。

    struct HitCheckJob : IJobParallelFor

    {

        [ReadOnly] public NativeArray<RaycastHit> hits;

        public NativeArray<float> velocities;



        public void Execute(int i)

        {

            // 加速度をセット、速度がマイナス(下に移動)、かつレイキャストの距離が一定以下だったらぶつかったとみなす。

            if (velocities[i] > 0 && hits[i].distance < 0.5f)

            {

                // ヒットしたので加速度を-2にセットして浮かび上がらせる。

                velocities[i] = -2;

            }


            velocities[i] += 0.098f;

        }

    }


Jobを定義する際にパラメータに要素をセットすることで、後ほど実行 = Schedule関数を呼ぶ時に第一引数にセットした数だけExecuteが回ってくれる。


hitsなどの要素のセットについては、このジョブのインスタンスを生成する時にhits = みたいな形にして渡す。

hitsは参照オンリーなので、ReadOnlyをつけることができる。(velocityはR/W両方あるのでなんもできん)


次に、レイキャストコマンドを実行する部分の次に、HitCheckJobを生成する部分を追加する。

    void Update()

    {


        var commands = new NativeArray<RaycastCommand>(targets.Length, Allocator.TempJob);

        var results = new NativeArray<RaycastHit>(targets.Length, Allocator.TempJob);


        for (var i = 0; i < targets.Length; i++)

        {

            var targetPosition = targets[i].position;

            var direction = Vector3.down;


            // 指定位置から下方向にレイキャストを行うコマンドをまとめる

            // RaycastCommand型は、結果にReycastHit型を返してくる。

            var command = new RaycastCommand(targetPosition, direction);

            commands[i] = command;

        }


        // ジョブの初期化をする

        var hitCheckJob = new HitCheckJob()

        {

            hits = results,

            velocities = velocity

        };


ここまでで、次の状態のhitCheckJobのインスタンスが手に入る。

・このあとRaycastの結果 = RaycastHitのNativeArrayを返してくるresultsの参照を、hitsに代入

・速度が入るvelocityのNativeArrayの参照を、Job内部で値を入れるvelocitiesに代入


そんでjobを実行。

        var commandJobHandle = RaycastCommand.ScheduleBatch(commands, results, 10);

        var hitcheckHandle = hitCheckJob.Schedule(targets.Length, 10, commandJobHandle);

        hitcheckHandle.Complete();


先ほどまでRaycastCommandの結果をそのままCompleteしていたのを、

新たにhitcheckHandleインスタンスをhitCheckJob.Scheduleから生成し、そのjobの完了を待つように変更する。


この際、まずレイキャストを打ってからヒットチェックがしたいため、hitcheckJobのSchedule関数にcommandJobHandleのインスタンスをセット、

必ず

commandJobHandle

hitcheckHandle

という順番で処理が実行されるようにする。


ここまでで、ヒットチェックがjob化できた。



移動もJob化する

あとは応用で、

・加速度分移動する

という処理をJob化する。


まず位置(transform)をいじるので、transformに対してJob内から干渉できるJobを作成する。

    struct ApplyPositionJob : IJobParallelForTransform

    {

        [ReadOnly] public NativeArray<float> velocities;


        public void Execute(int i, TransformAccess transform)

        {

            transform.localPosition += Vector3.down * velocities[i];

        }

    }


こんな感じで、IJobParallelForTransform structを拡張したジョブを定義する。

Executeの内部処理についてはちょっと特殊で、


・IJobOarallelForTransform関数のSchedule関数はTransformAccessArray(Transform[] transforms)という型を引数にとり

・Execute実行時に transforms へのアクセスが可能なように引数に入っている

という感じ。


Transformそのままだと参照型になってしまっていて値型ではないのでJobからアクセスできない、というのがあるらしい。

なので、

        var transformAccess = new TransformAccessArray(targets);


とか定義して、Schedule関数に対して渡す。

さらにScheduleの第二引数としてヒットチェックのjobHandleを渡し、順番を制御する。

        var applyPosHandle = applyPositionJob.Schedule(transformAccess, hitcheckHandle);


これで、

・レイキャスト

・ヒットチェック

・移動


の順番で処理が行われるようになっている。

処理が終わったら

        transformAccess.Dispose();


も忘れないようにする。ない場合エラー出してくれるんで便利。


ここまででヒットチェックと移動のJob化ができた。やったぜ。

この時点で100fps前後。まあ変わらん。


Raycast、Hitcheck、ApplyPosがJob化できた図。

スクリーンショット 2019-01-06 0.10.59.png


ここからさらに高速化するには、「Completeをやめてメインスレッドのロックを外す」ということをする感じになる。



Completeを次のフレームで実行する(WaitForJobGroupにかかる時間 = メインスレッドでの待ちを減らす)

Updateで行うコードを次のような感じにする。


    void Update()

    {


        // applyPosHandle の終了を待つ

        applyPosHandle.Complete();


        for (var i = 0; i < targets.Length; i++)

        {

            var targetPosition = targets[i].position;

            var direction = Vector3.down;


            // 指定位置から下方向にレイキャストを行うコマンドをまとめる

            // RaycastCommand型は、結果にReycastHit型を返してくる。

            var command = new RaycastCommand(targetPosition, direction);

            commands[i] = command;

        }


        // ジョブの初期化をする

        var hitCheckJob = new HitCheckJob()

        {

            hits = results,

            velocities = velocity

        };


        var applyPositionJob = new ApplyPositionJob()

        {

            velocities = velocity

        };


        // レイキャスト、ヒットチェックまでは変わらず、applyPosのハンドルをグローバル変数に入れる。

        var commandJobHandle = RaycastCommand.ScheduleBatch(commands, results, 10);

        var hitcheckHandle = hitCheckJob.Schedule(targets.Length, 10, commandJobHandle);

        applyPosHandle = applyPositionJob.Schedule(transformAccess, hitcheckHandle);

    }


applyPosHandleをグローバルに定義して、その終了待ち=CompleteをUpdateの先頭で行う。

グローバル化に祭して、いままでUpdateの最後でDisposeしていたテンポラリなNativeArrayもすべてグローバルな定義に変わる必要がある。

Jobのインスタンス生成(参照渡し)と、レイキャストコマンドの生成/セットは変わらず。


この時点で103fpsくらいになった。ちょっと高速化。

プロファイラを見てみると、Update関数が実行されてからJobが実行されている。やったぜ。


スクリーンショット 2019-01-06 0.35.45.png


あと、WaitForJobIDが消えた。(乗らないくらい短いか、見落としてるか。)



ちょっとBurst化してみる

JobをBurstCompiler任せにしてみる。

Job定義のstructに BurstCompile のアノテーションをつけるだけ。


-> 爆速になった。

110fpsくらい出てる。



値を得られるようにする

IJobを拡張したstructを用意する。

    struct IsHit : IJob

    {

        [ReadOnly] public NativeArray<RaycastHit> hits;

        [WriteOnly] public NativeArray<int> isHit;


        public void Execute()

        {

            for (var i = 0; i < hits.Length; i++)

            {

                // 距離が1fより小さかったら、ヒットしている

                if (hits[i].distance < 1f)

                {

                    isHit[0] = 0;

                    return;

                }

            }


            // それ以外であればすべてのインスタンスがヒットしてない

            isHit[0] = 1;

        }

    }


Update内でヒットのハンドルを生成、ここでサイズ1のNativeArray<int>を入れる。

        var hitHandle = new IsHit()

        {

            hits = results,

            isHit = new NativeArray<int>(1, Allocator.TempJob)

        };


        // レイキャスト、ヒットチェックまでは変わらず、applyPosのハンドルをグローバル変数に入れる。

        var commandJobHandle = RaycastCommand.ScheduleBatch(commands, results, 10);


        var isHitHandle = hitHandle.Schedule(commandJobHandle);

        var hitcheckHandle = hitCheckJob.Schedule(targets.Length, 10, commandJobHandle);


        applyPosHandle = applyPositionJob.Schedule(transformAccess, hitcheckHandle);


        // ヒット判定だけは即座に終了させる

        isHitHandle.Complete();


        var isHit = hitHandle.isHit[0];

        if (isHit != 1)

        {

            Debug.Log("ヒットした");

        }


        // hitHandleisHitはこのブロック内で生成しているパラメータなので、ここで消費する。

        hitHandle.isHit.Dispose();


isHitHandleを生成、レイキャストのあとに実行する。

で、ヒット判定だけをCompleteにして値を受け取李判断に使う。便利。



コルーチン化する

ちょっとは書きやすくなるか?

    IEnumerator Start()

    {

        var applyPosHandle = default(JobHandle);

        var commands = new NativeArray<RaycastCommand>(targets.Length, Allocator.Persistent);

        var results = new NativeArray<RaycastHit>(targets.Length, Allocator.Persistent);


        var transformAccess = new TransformAccessArray(targets);

        var velocity = new NativeArray<float>(targets.Length, Allocator.Persistent);


        for (int i = 0; i < targets.Length; i++)

        {

            velocity[i] = 1;

        }


        disposeAct = () =>

        {

            try

            {

                applyPosHandle.Complete();


                velocity.Dispose();

                commands.Dispose();

                results.Dispose();

                transformAccess.Dispose();

            }

            catch { }

        };


        // ジョブの初期化をする

        var hitCheckJob = new HitCheckJob()

        {

            hits = results,

            velocities = velocity

        };


        var applyPositionJob = new ApplyPositionJob()

        {

            velocities = velocity

        };


        while (true)

        {


            for (var i = 0; i < targets.Length; i++)

            {

                var targetPosition = targets[i].position;

                var direction = Vector3.down;


                // 指定位置から下方向にレイキャストを行うコマンドをまとめる

                // RaycastCommand型は、結果にReycastHit型を返してくる。

                var command = new RaycastCommand(targetPosition, direction);

                commands[i] = command;

            }


            var hitHandle = new IsHit()

            {

                hits = results,

                isHit = new NativeArray<int>(1, Allocator.TempJob)

            };



            // レイキャスト、ヒットチェックまでは変わらず、applyPosのハンドルをグローバル変数に入れる。

            var commandJobHandle = RaycastCommand.ScheduleBatch(commands, results, 10);


            var isHitHandle = hitHandle.Schedule(commandJobHandle);

            var hitcheckHandle = hitCheckJob.Schedule(targets.Length, 10, commandJobHandle);


            applyPosHandle = applyPositionJob.Schedule(transformAccess, hitcheckHandle);


            // ヒット判定だけは即座に終了させる

            isHitHandle.Complete();


            var isHit = hitHandle.isHit[0];

            if (isHit != 1)

            {

                Debug.Log("ヒットした");

            }


            // hitHandleisHitはこのブロック内で生成しているパラメータなので、ここで消費する。

            hitHandle.isHit.Dispose();


            yield return null;


            // applyPosHandle の終了を待つ

            applyPosHandle.Complete();

        }

    }


NativeArrayとか、jobHandleの生成を一度きりにできた。

参照だけをなんとかできるのが良い。



まとめ


コード全体を書いとく。

using System;

using System.Collections;

using System.Collections.Generic;

using Unity.Burst;

using Unity.Collections;

using Unity.Jobs;

using UnityEngine;

using UnityEngine.Jobs;


public class JS : MonoBehaviour

{

    [SerializeField] Transform[] targets;


    [BurstCompile]

    struct HitCheckJob : IJobParallelFor

    {

        [ReadOnly] public NativeArray<RaycastHit> hits;

        public NativeArray<float> velocities;



        public void Execute(int i)

        {

            // 加速度をセット、速度がマイナス(下に移動)、かつレイキャストの距離が一定以下だったらぶつかったとみなす。

            if (velocities[i] > 0 && hits[i].distance < 0.5f)

            {

                // ヒットしたので加速度を-2にセットして浮かび上がらせる。

                velocities[i] = -2;

            }


            velocities[i] += 0.098f;

        }

    }


    [BurstCompile]

    struct ApplyPositionJob : IJobParallelForTransform

    {

        [ReadOnly] public NativeArray<float> velocities;


        public void Execute(int i, TransformAccess transform)

        {

            transform.localPosition += Vector3.down * velocities[i];

        }

    }


    [BurstCompile]

    struct IsHit : IJob

    {

        [ReadOnly] public NativeArray<RaycastHit> hits;

        [WriteOnly] public NativeArray<int> isHit;


        public void Execute()

        {

            for (var i = 0; i < hits.Length; i++)

            {

                // 距離が1fより小さかったら、ヒットしている

                if (hits[i].distance < 1f)

                {

                    isHit[0] = 0;

                    return;

                }

            }


            // それ以外であればすべてのインスタンスがヒットしてない

            isHit[0] = 1;

        }

    }


    private Action disposeAct = () => { };


    IEnumerator Start()

    {

        var applyPosHandle = default(JobHandle);

        var commands = new NativeArray<RaycastCommand>(targets.Length, Allocator.Persistent);

        var results = new NativeArray<RaycastHit>(targets.Length, Allocator.Persistent);


        var transformAccess = new TransformAccessArray(targets);

        var velocity = new NativeArray<float>(targets.Length, Allocator.Persistent);


        for (int i = 0; i < targets.Length; i++)

        {

            velocity[i] = 1;

        }


        disposeAct = () =>

        {

            try

            {

                applyPosHandle.Complete();


                velocity.Dispose();

                commands.Dispose();

                results.Dispose();

                transformAccess.Dispose();

            }

            catch { }

        };


        // ジョブの初期化をする

        var hitCheckJob = new HitCheckJob()

        {

            hits = results,

            velocities = velocity

        };


        var applyPositionJob = new ApplyPositionJob()

        {

            velocities = velocity

        };


        while (true)

        {


            for (var i = 0; i < targets.Length; i++)

            {

                var targetPosition = targets[i].position;

                var direction = Vector3.down;


                // 指定位置から下方向にレイキャストを行うコマンドをまとめる

                // RaycastCommand型は、結果にReycastHit型を返してくる。

                var command = new RaycastCommand(targetPosition, direction);

                commands[i] = command;

            }


            var hitHandle = new IsHit()

            {

                hits = results,

                isHit = new NativeArray<int>(1, Allocator.TempJob)

            };



            // レイキャスト、ヒットチェックまでは変わらず、applyPosのハンドルをグローバル変数に入れる。

            var commandJobHandle = RaycastCommand.ScheduleBatch(commands, results, 10);


            var isHitHandle = hitHandle.Schedule(commandJobHandle);

            var hitcheckHandle = hitCheckJob.Schedule(targets.Length, 10, commandJobHandle);


            applyPosHandle = applyPositionJob.Schedule(transformAccess, hitcheckHandle);


            // ヒット判定だけは即座に終了させる

            isHitHandle.Complete();


            var isHit = hitHandle.isHit[0];

            if (isHit != 1)

            {

                Debug.Log("ヒットした");

            }


            // hitHandleisHitはこのブロック内で生成しているパラメータなので、ここで消費する。

            hitHandle.isHit.Dispose();


            yield return null;


            // applyPosHandle の終了を待つ

            applyPosHandle.Complete();

        }

    }


    void OnDisable()

    {

        disposeAct();

    }

}




JobSystemは、次のようなもの

・IJob系を継承したstructを定義すると、Executeメソッド内がworkerスレッド内で実行される。

IJob Execute()

IJobParallelFor Execute(index)

IJobParallelForTransform Execute(index, transformAccess)


など、namespace Unity.Jobs 以下のもの。

これにより、Execute内に書いた処理がworkerスレッドで分散して高速に実行される。


Executeメソッド内では、structに定義したパラメータに触れるほか、indexを使ってパラメータの特定のindexに対して変更をかけたりができる。


イメージ的には、Executeメソッドは一つのworkerスレッドからアクセスされるものではなく、

複数のworkerスレッドから実行されえる。そのため、indexパラメータが渡ってくるがその実行元がどのworkerかはわからない。



・IJob系のstructをインスタンス化し、Schedule関数を実行すると、Jobがスケジューリングされてworkerスレッドで実行される。

インスタンス化時に、各ジョブを跨いで編集する対象をセットする。


JobAインスタンス{ param1 = shared1 }

JobBインスタンス{ param2 = shared1 }

のように、shared1というパラメータを各ジョブで共有させることで、一つのパラメータを複数のジョブでガチャガチャ編集することができる。



・Jobのスケジューリング時に、引数として

IJob Schedule(完了を待つほかのJob)

IJobParallelFor Scuedule(扱う対象の数, 分散するworker数みたいな数値, 完了を待つほかのJob)

IJobParallelForTransform Scuedule(TransformAccessArray, 完了を待つほかのJob)

などを渡せる。



・Jobの実行待ちは、Complete関数で行うことができる。



・NativeArray<T>を使って、Job(Workerスレッド)からアクセスする要素を定義する。



・NativeArray<T>はかならずDisposeする必要がある。



wrote 2018/12/09 22:33:42

gotanda.unity#9行ってきた


概要

これ

https://gotanda-unity.connpass.com/event/105701/



体が闘争を求めたり(https://twitter.com/Raspberly/status/1067815579145273344)、VJを求めたり(https://twitter.com/hacha/status/1067796141830397953)していた。



自分の方はなんつーかだいぶアガって喋っていてうーんという感想なんだけど、

URLCachingっていうAutoyaの機能の一個について話してた。


死霊

https://speakerdeck.com/sassembla/urlcaching-in-unity




URLCachingの今

crcチェックとか自前で実装しないとねーと言ってたんだけど、簡単に実装する方法が思いついた。

なんのことはない、URLに crc=eu9euoie とかちゃんとしたcrcを入れて、

URLCachingの成功時のハンドラでチェックすればいいんだ。


なんかサンプルに足しとこうと思う。

wrote 2018/11/30 11:50:12

ECS完全理解


概要

これ 

「Unity ECS完全に理解した」

https://connpass.com/event/101774/



ドカベンさん


前提

Worldインスタンスに対してComponetSystemが1:1対応

DefaultWorld というのがデフォである。


動作

Transform、Render、EnemyGenerate、、みたいにSystemを作り、

それぞれに前提というか適応ルールをセットする。

e,g, Pos,Rotate,Scaleのどれかがあれば -> PlayerやEnemyのエンティティにヒットする。


用語の整理

ComponentData


Entity

システムに対するインデックスの定義。


var arch = entityManager.CreateArchetype(条件要素)

var entity = arch.なにやら



ECSの描画について

サンプルあり。



衝突判定

そのうち公式実装されるかも。



のたぐす


ECSでパーティクル実装するメソッド

・GOよりオーバーヘッド低い

・C#でコントロールできる


Entityを作る -> それを扱うSystemを作る -> 動かす


random.NextFloat3Direction

そんなのあるんだww



一定時間経過したら削除

ウッッッ見失った、、、



軌跡

一定個数の通った位置を保持

要素をBufferArrayで定義、生成。


RemoveAt[index]などで削除を行う。



描画

Graphics.DrawMesh

MarkDynamicでちょっと早くなる?



高速化

GPUへ送る情報を減らすと高速化できそう -> 減らす。

DrawMeshInstancedIndirect でバッチで渡す。


頂点数分の長さのパイプ(20パーツ)を作って、Trailにする。

Segment + 要素に分割


一旦データをNativeArrayに入れる -> ComputeBufferに入れる流れ。


NativeArray、Tempで毎回取得するより必要になったタイミングで獲得する流れのほうがよい -> エディタでやるとTempのほうが遅いらしい。



Es


Hybrid ECS

既存のプロダクトを手っ取り早く良くしたい

メインスレッドの占有時間を7 -> 0.4まで減らす話


Transformを扱う上では結構あり(素敵)


1つのGOから1Entityを生成

従来の開発スタイル + ECS



Hybrid特有

GOからEntityの値を書き換える、EntityからGOのコンポーネントを書き戻す

GameObjectEntityを使う。


ComponentDataWrapper を継承することで、GOに貼れる。

CopyTransformToGOSysytem というSystemが標準で提供されている。

LT


NativeSetThreadIndex アトリビュート

ほーーこんなのが。









wrote 2018/10/22 19:16:43

Live2Dの除霊記録


概要

除霊した。成仏してくれ。



やばかったところ

OnPostprocessAllAssets ってあるじゃない。


ドキュメント

https://docs.unity3d.com/ScriptReference/AssetPostprocessor.OnPostprocessAllAssets.html


大事なこととしては、

「このAPIは全体で1回だけ走ります」とか

一切書いてないことで。


つまりこのメソッド、Unityが「あー全部読み込み終わったわ~」ってなったら、いつでも着火する可能性があるんだな。



で、Live2DのPostprocessではこのメソッドにフックする形でResourcesの生成やモデルのインポート時処理をしており、

これは複数回呼ばれる必要が全くないのに不必要に何回も呼ばれてしまうことがある。


結果的に、

「開いていたシーンに謎のサンプルキャラクターが発生する」

「無限にインポートが発生して終わらない」

などが起こり得る。


除霊内容

・Assetがnullな時にAssetDatabaseを使わない(string.Emptyが返ってくる

・Live2Dがインストールされている箇所の取得を行う


などをやった。



Assetがnullな時にAssetDatabaseを使わない(string.Emptyが返ってくる

Live2Dの中で、Resourcesに入っているAssetの読み込み順が不自然だった時に発生する。

OnPostprocessAllAssets は、そりゃあまあ最後のインポート後に実行される、、はずなんだけど、どこを「最後」とみなすかはUnity次第で。


これが、例えば「Live2Dのインポートが終わる前に、別の仕掛けでリソース生成をして、

そのimportが終わった」みたいな悪魔のようなタイミングで発生するとどうなるか。


Live2Dでは、AssetDatabaseに対してimport済みのResourceを突っ込む処理があり、その時、このResourceがnullな可能性がある。

で、null を放り込むとどうなるか?


返ってくるのはstring.Emptyなんだこれが。


初めて知ったけどさ。


AssetDatabaseに対して検索目的でAssetを放り込む場合、

・nullチェックして

・AssetDatabaseに放り込む


とかをやったほうがいい。少なくとも返ってきたものがstring.Emptyじゃないかどうかみたいなチェックはすべきだ。


Live2Dのコードはそういうのをやってなかったので、見事にstring.Emptyが入った。

で、入った結果どうなるか?


ルート/Materials みたいなところにリソースを作ろうとする。当然これはaccess denyされる。


この辺は次のように解決できる。

・Assetのリファレンスを使わない(パスベースで解決する。

・ディレクトリはある? あるなら生成が成功してるはず。


みたいな。 Resource系で、nullになり得るものを信用してはいけない(教訓)。


Live2Dがインストールされている箇所の取得を行う

Live2D、デフォルトパス以外にAssetが移動することが考慮されてない。

Live2D自体のパスの導出に失敗して、前出のインポートエラーが起きたりする。


対策は2つで、

1.絶対に動かすなよって感じにガチガチに縛る。例えばSDK実行時にAssets直下でなかったらエラー出す。

2.動かしてもいいように作る


オススメは2。利用しやすいほうが利用される。そして絶対パスは大体変なバグを生む。


wrote 2018/10/20 11:20:18

AssetFileHashが一貫性を失うタイミングについて


概要

Addressablesがうまいこと完成しても、中で使っているのはAssetBundle。はい。


AddressablesはABの作成からダウンロード用のリストの生成、それを起動時に取得しての、オンデマンドや範囲による一括取得を可能にしている(動けば)

ただ、中身はまんまABを使うオープンソースのコントローラ、というかフレームワークで、

まあ、フレームワークってことはユースケースしっかり判断して使おう・使わないでおこう を決めようなというところ。


そしてABには、特にABの更新に関わる crc 、hash という2つのパラメータがある。


crcって何

cyclic redundancy check、要するに、データが変更されたかどうかをチェックするための値。

エラー訂正(データの内容が期待してたんと違う)みたいなのを検知することができる。


ABで使われているcrcは、その生成にABの内容、中身のファイルの生成時の時刻などを使用しているらしく、

中身のAssetが変化するたびに変わる。(そりゃそう)

この変化によって、例えば次のようなことをやっている。


AB1を生成

-> AB1のcrcはこれ

-> どっかにメモっておく

-> クライアントアプリケーション側でメモを取得

-> AB1をダウンロード

-> メモのcrcと比較して、欲しかった「作った時のAB1のcrc」と、取得してきたAB1のcrcがマッチするかを見て、ちゃんとダウンロードできたか確認。


実は、このフローのうち、[AB1をダウンロード]以降は、UnityWebRequestのABダウンロード用の関数の引数がそのままその用途をなしている。


APIとしてはこのへん。


public static Networking.UnityWebRequest GetAssetBundle(string uri, uint crc);

https://docs.unity3d.com/ScriptReference/Networking.UnityWebRequestAssetBundle.GetAssetBundle.html


ここのcrcが、まさに「これからダウンロードするABのcrcに対して、マッチするのを期待するcrc」という値になっている。


ちなみにcrc入れて期待したのと違うのが帰ってくると、エラーが出て(表示だけのエラー、キャッチできない、今回落としたABは保存されない)、ダウンロードしたABはnullになる。


webからのダウンロードはファイルがぶっ壊れることがままあって、crcによる「落としたファイルが正しいか」みたいな処理は必須になっていると思う。


で、このcrcは、AB作成時にmanifestファイルに書いてある。


nestedprefab.manifest

ManifestFileVersion: 0

CRC: 2200902407

Hashes:

  AssetFileHash:

    serializedVersion: 2

    Hash: c088a4b2797e99ed3c95d8ce957816af

  TypeTreeHash:

    serializedVersion: 2

    Hash: 11817dad4d3c8e9c24248d58700284ea

HashAppended: 0

ClassTypes:

- Class: 1

  Script: {instanceID: 0}

- Class: 4

  Script: {instanceID: 0}

- Class: 23

  Script: {instanceID: 0}

- Class: 102

  Script: {instanceID: 0}

- Class: 114

  Script: {fileID: 11500000, guid: 7e73406419bf54a50a1b5faf24749c6c, type: 3}

- Class: 115

  Script: {instanceID: 0}

Assets:

- Assets/AutoyaTests/RuntimeData/AssetBundles/MainResources/nestedPrefab.prefab

Dependencies:

- /Users/passepied/Desktop/autoya/Editor/AssetGraph-1.3-release/UnityEngine.AssetBundleGraph/Cache/AssetBundles/4e024a18-af2d-4f29-9f4b-1212e005d1ea/iOS/texturename1


赤字のところがcrc。

UnityはABを生成するとき、1つのABに対して1つのcrcを計算し、それを記述したmanifestファイルを吐く。


で。crcには、Unityのプロジェクトの形態を無茶苦茶にしても一貫した値を出す、という結構強い一貫性がある。

具体的には、昨今みんながやってるであろう「Libraryフォルダをバージョン管理しない」みたいなことをしても、ちゃんと一貫したcrcを出す。


crcの一貫性とプロジェクト形態の例

・これはLibraryフォルダが無い状態からでも同じcrcを出す

・たぶんABにする対象のアセットのmetaファイルの値さえしっかりしてればOK

・metaファイルすら失うと死(metaが作り直されてABのcrcも当然変わる


Libraryフォルダをgithubとかに上げないでもいい、みたいなのはみんなやってると思ってる。だから、

Libがなくてもcrcが変わらない、という事態は大変好ましい。



問題はhashだ。


hashって何

hashもUnityのAB取得のAPIに記載がある。


public static Networking.UnityWebRequest GetAssetBundle(string uri, Hash128 hash, uint crc);

https://docs.unity3d.com/ScriptReference/Networking.UnityWebRequestAssetBundle.GetAssetBundle.html



それと、以前書いたhashに関する記事で、hashって何?どう使うの?ってのを紹介している。


Caching.IsVersionCached(url, hash) ってどういう挙動?

http://sassembla.github.io/Public/2017:02:10%2013-56-21/2017:02:10%2013-56-21.html



んでこのhash、どうやってつけるのがいいんだろう、って悩むんだけど、なんとABを生成した時に出るmanifestファイルに2種類のhashが書いてある。

ManifestFileVersion: 0

CRC: 2200902407

Hashes:

  AssetFileHash:

    serializedVersion: 2

    Hash: c088a4b2797e99ed3c95d8ce957816af

  TypeTreeHash:

    serializedVersion: 2

    Hash: 11817dad4d3c8e9c24248d58700284ea

HashAppended: 0

ClassTypes:

- Class: 1

  Script: {instanceID: 0}

- Class: 4

  Script: {instanceID: 0}

- Class: 23

  Script: {instanceID: 0}

- Class: 102

  Script: {instanceID: 0}

- Class: 114

  Script: {fileID: 11500000, guid: 7e73406419bf54a50a1b5faf24749c6c, type: 3}

- Class: 115

  Script: {instanceID: 0}

Assets:

- Assets/AutoyaTests/RuntimeData/AssetBundles/MainResources/nestedPrefab.prefab

Dependencies:

- /Users/passepied/Desktop/autoya/Editor/AssetGraph-1.3-release/UnityEngine.AssetBundleGraph/Cache/AssetBundles/4e024a18-af2d-4f29-9f4b-1212e005d1ea/iOS/texturename1


自分はこのうちでAssetFileHashを使うことが多い。

まあぶっちゃけ、ここでのhash自体は

・ABの要素が変わった時に自動的に変わってくれるとうれしい

・ABの要素が変わらないなら変わらないでいてほしい


という感じで、このAssetFileHashは「今まで自分が知る限り」その用途を果たしてくれていた。


が。


がだ。


その前提が砕けるタイミングがあった。(本題)



AssetFileHashが全くランダムに作られてしまうタイミングがある

ぶっちゃけて、Libraryフォルダを生成するタイミングで、AssetFileHashの値が無駄に変化する。

この、Libraryフォルダを作り直すとAssetFileHashの一貫性が破綻する状況は、次のようなシナリオで露見した。


1.あるプロジェクトでABを生成することになった

2.まずはPC1で適当にABを生成していた

3.ABのhashパラメータとしてはAssetFileHashを使用していた

4.hashはAという値を出していた

5.githubとかでプロジェクトをバージョン管理、Libraryフォルダは含めない(要らないからね!!)

6.別のPC、PC2にプロジェクトをpullしてきて展開、このタイミングではLibraryフォルダはない。

7.Unityを起動すると、Libraryフォルダが生成される。

8.ここでPC2でABを作成すると、アセットは変化していないのでcrcやサイズなどは一切変化しないが、AssetFileHashは 3. の時とは別の値を生成する。なんでやねん。


なんとなく嫌な予感がして調べてもらったところ完全に上記の状況がヒットして、ぐえーーってなっていた。



AssetFileHashはLibraryフォルダが共有されないと一貫性を失ってしまう


つまり

・それまで変化がなければ一定の値を保っていた

・変化があった時「のみ」変わっていた

という特性だと思っていたのが、Libraryフォルダを生成するようなことがあるとこの一貫性が破綻する。


一応、Libフォルダが生成されることがトリガーで値が変わる、というのがわかっている状態だが、

これは例えば、


「先祖代々ABを作成していたマシンが死んだ」

「新たにABを生成するマシンにプロジェクトをpullして~」


みたいなタイミングで牙を剥く。


具体的にいうと、

アプリ側でABDLに際してhashチェックするようなコード書いてると

すべてのABが更新されたような挙動になってしまう。実際にはなにも変わっていないのに。


んんん~~~AssetFileHash なんでやねん。



というわけで、ABのhashには、AssetFileHashとは違った値を使おう。

オススメは次の特性を満たす値。

・crcのように、ファイルの内容が変わったら10000%変わる値

・上記以外の要素を一切含まない値


自分はどうするかな~~ ABの名前とcrcからhash作るかな。

そのうちこの辺に反映される。

https://github.com/sassembla/Autoya/blob/master/Assets/Editor/Autoya.AssetGraphIntegration/AutoyaAssetBundleListGenerateProcess.cs#L278



Addressablesが将来、このhash要素の概念を守ってくれていると嬉しい。(また最新見てみよう。)


あ、バグ、、とかそういう線はあるのかな、、うーん、、、



こちらからは以上です。

wrote 2018/09/02 10:17:07

Unity(IL2CPP環境)でのprotobufの使い方


概要

今年4月のprotobuf側の改修以降、IL2CPPのAOT対策が組み込まれたため、お世話になることが多いので解説を書く。



Protobuf is 何

ProtocolBufferというデータ形式。

データ -> protobuf形式(byte[]) -> データ というような変形ができる。


公式

https://developers.google.com/protocol-buffers/


特徴は、

・どんなデータを扱いたいかを定義した.protoという形式のファイルを書く

・エディタライブラリが定義ファイルからえいやっといろいろな言語向けのSerialize/Deserialize用コードを生成する(いろんな言語の実装が生成できる

・開発者は生成されたコードを叩くようなコードを書き、いろんな言語のインスタンス -> protobuf形式のデータ -> インスタンス とかの変形ができるようになる


syntax = "proto3";


message SearchRequest {

string query = 1;

int32 page_number = 2;

int32 result_per_page = 3;

}


protoファイルをサーバとクライアントで共有しとけばあとはなんとかなる的な。



また、oneofという修飾句があり、複数のクラスを含むような定義をしたあと、その中の「どれか一つだけが実際に入っている」という状態のデータを表現できる。

oneof accessor

https://developers.google.com/protocol-buffers/docs/proto3#oneof


これは大変便利で、


oneofSample.proto

message DataA { ... }

message DataB { ... }


message Box {

oneof dataBox {

DataA dataA = 1;

DataB dataB = 2;

}

}


とか作っておくと、

ネットワーク越しにbyte[]を受け取る -> とりあえずadtaBoxでDeserializeする -> dataBoxのタイプを判定、DataAかDataBのどちらかが入っている、というのが、次のようなコードでわかる

(C#)

byte[] messageBytes; // ネットワークから受け取ったデータが入ってると思って。


var box = new Box();

((IMessage)box).MergeFrom(messageBytes);


switch (box.MsgCase)

{

    case Box.MsgOneofCase.DataA:

        {

            var dataA = box.dataA;

.....


            break;

        }

    case Box.MsgOneofCase.DataB:

        {

            var dataB = box.dataB;

.....


            break;

        }


みたいな感じに、switchで中身を把握することができたりする。

これは一つの経路で複数のデータを扱う時に重宝する。


送る側は単にboxを作って好きなデータを一種だけ入れればよい。簡単。



使い方


1.protobufのライブラリをマシンにインストールする

mac: homebrewが入っていれば、

brew install protobuf


homebrew 何? って人は https://brew.sh


Windows: chocolateが入っていれば、

choco install protoc


chocolate 何?って人は https://chocolatey.org


これはコマンドラインツールになっていて、インストール後であればどこからでもprotocコマンドが呼べる、、はず。



2. .protoファイルからコードを生成する

protoc --csharp_out=. --proto_path=. protocol.proto


--csharp_out オプションで、出力する言語をC#にセット、パスを現在のパスに指定、

--proto_path オプションで、import(他のprotoファイルの参照)を探すパスを現在のパスに指定、

使用するprotoファイル名を記述、 というような感じ。


これで、protoファイルがあるのと同じパスに指定した言語のコードが生成される。



ここまでの工程で、C#で使えるSerializer/Deserializerのコードが自分のライブラリで使えるようになる。 簡単。


Unityでの一手間

IL2CPPの都合として、実行時にReflection.Emitが使えない、というものがある。

で、protobufはモロにこれを、byte[]からインスタンスを作る過程で、生成するインスタンスの型情報を取得するために使う。


2018年4月くらいにprotobufのC#コードに手が入り、使用したいデータ型をあらかじめコードに書くことでReflection.Emitが発生しないようになる、

= Unity + IL2CPPで使えるようになる、というメソッドが追加された。


using Google.Protobuf.Reflection;


FileDescriptor.ForceReflectionInitialization<データ型>();

この1行で、指定したデータ型を、IL2CPP環境で実行しても問題が発生しないようにできる。


ちなみにoneofを使っているデータ型を指定するとその内部のデータ型もすべてセーフになる。やったぜ平和。




wrote 2018/08/05 1:07:27

TextMesh ProとuGUIで文字レイアウトを取得する


概要

文字をCanvas上とかに出すじゃない。

そんなとき、

「この文字列はこのフィールド上でどんな感じに改行されるの?」

とかを事前に知りたくなるじゃない。なるよね?


それぞれこんな感じで取得できる。



uGUI

// Text textComponent みたいなものに対して

// TextGenerator generator = new TextGenerator(); みたいなのをグローバルで取得しておいて使い回すことができる


var text = "なんか特定の広さの領域に表示してどう改行されるか知りたい文字列";


// 使い回すならinvalidateで過去の情報を消す必要がある

generator.Invalidate();


// コンポーネントにテキストをセットする。

textComponent.text = text;


var setting = textComponent.GetGenerationSettings(new Vector2(viewWidth, float.PositiveInfinity));

generator.Populate(text, setting);



var lineCount = generator.lineCount;

var lines = generator.lines;// 各行の情報、行の高さとかspacingの高さが取れる


太字の行の処理でgeneratorにレイアウト情報が入る。

レイアウトするサイズ情報をいくらでも好きなように設定、レイアウトを試すことができる。


取得できる情報は、全体の行数と各行の情報。大元の文字列のどこからどこまでがこの行、とかのインデックスも入っている。



TextMesh Pro

// TMProのコンポーネント TMPro.TextMeshProUGUI textComponentというのがあったとして


var text = "なんか特定の広さの領域に表示してどう改行されるか知りたい文字列";


textComponent.text = text;


// textComponentに対してwidthをセットする必要がある。高さは無限設定でOK

textComponent.rectTransform.sizeDelta = new Vector2(viewWidth, float.PositiveInfinity);


// このメソッドは、コンポーネントがgameobjectにアタッチされて、かつgameobjectがcanvasに乗っている場合のみ動作する。

var textInfos = textComponent.GetTextInfo(text);


// 各行の要素とパラメータを取得する。

var tmGeneratorLines = textInfos.lineInfo;

var lineSpacing = textComponent.lineSpacing;

var tmLineCount = textInfos.lineCount;


太字の行の処理でgeneratorにレイアウト情報が入る。

まず TMPro.TextMeshProUGUIコンポーネント のrectTransformを弄る。こうすることで描画されるサイズが変わる。

uGUIとは異なりcanvas上に配置されたgameobjectにTMPro.TextMeshProUGUIコンポーネントがアタッチされている前提でないと動作しない。


取得できる情報はuGUIと大差ない。


wrote 2018/08/04 8:23:25

おなかソフトのDon't Destroy On Load #1に行ってきた


概要

このこれ

Drecom Tech Espresso #6 "おなかソフトのDontDestroyOnLoad"

https://drecom.connpass.com/event/93534/

当日の様子はなんか動画として上がるようなので期待して待ってる。





あとは全部おまけというかとりあえず事前に考えをまとめておこうと思って書いたアンチョコ(アバターのフェイスキャプチャが繊細すぎて本当に目が離せなくて全く見れなかった。(ちょっと文がぶっちぎれ過ぎているので捕捉した。


ゲームのSingletonどう思う?

直感的には、ゲーム要素に関して何か保持しているシングルトンは、8割くらいで負債になる、設計の放棄。

ようは 状態を持った グローバル関数 なので、そりゃやばかろうよという感じになると思う。


Sigletonを使うと可換性にものすごい問題を来たす。アクセスが容易すぎるんで、いろんなところから接続できて、その前提を元にコードが書かれる。

ここで問題なのは、安易に接続させてしまうことで、接続する側が後世に渡って受ける設計的な影響力が大きすぎること。



「どうすれば可換な状態を維持できるか」というのに注目すると、ゲーム内Singleton作ってもすぐ捨てないとだめみたいな気分になると思う。


逆に、目的が「それ」 = どこからでもアクセスできてしかるべきもの、ならば存在してアリだとは思っている。(サウンドマネージャとか認証系とかリソースロード系とか、ゲームのコア以外の部分のデータの持ち回しとか)


Autoyaもそんな感じで、あれは認証 + Asset管理 + サーバからのバージョンコントロールを行うための「状態」を保持したシングルトンになっている。

リセッタとか完備してあったり作り直せるようになってるのでテストできる。


だが、やはり「ゲームの、まさに遊ばせるためのコードの中身」ではない。脇役なのでこの構造を許している。



Unity + ゲーム内Singletonでよくある悪

テストの邪魔

全てのタイミングを貫通して状態を持ってしまう + 閉鎖的、というのがネック。

毎回作り直すためにプログラムのコンテキスト自体を作り直すとかの力技が必要

欲しいのはSingleton? それとも一定区間だけアクセス可能なステートマシン?



本来あるべきではない公開度合いと、それによる密結合

どこからでもアクセスできる、というのがまず設計的な間違いとして露見してくるパターンがほとんどで、

実際に必要だったのはもっと小さなスコープ、もっと狭いアクセス範囲ということが多い。

だのにグローバルに置いてしまって、「今シングルトンを止めるには、シングルトンに依存している側を大規模に書き直さないといけない」などが発生する。

つまりシングルトンは「将来のコードの変更可能性を下げる」楔なのだ。


グローバルではなく、何らかの関係性の何らかのタイミングへの隠蔽、みたいなのが理想で、これは最初からグローバルで作ってしまうと後から直すのが大変。


SingleMonoBe

自分は一切お世話になったことがないのでよくわからない。だいたいシーンごとに用意した代替を使ってしまう。

MonoBeが必要なポイントは後述するが、限られているので、こう、はい。


おまけ:MonoBehaviourの使い所について考えよう

・Unityと開発者をつなぐ場所

・メインスレッドへのエントリーポイント

-> つまりメインスレッドでしかできないことをするための場所

それだけのためにMBがあればいいのではというね。


昨今はおもしろコンパイラやおもしろシステムもあることだし、この考え方は変わらないのかなあと思っている。C#で書く場所で頑張らない。



Unityのメインスレッド制約

GUI操作、オーディオ、コンポーネントへの干渉などの起点はすべてこの制約がある。

この制約のせいで、グローバルからこういう操作呼びたいな~~ってなると、どうしてもMonoBehaviourが必要になる。


で、これをグローバルに一個だけ置ければいいのでは -> 状態も持たせちゃおう(バカ) -> つらい、、


Updateとか一個の方が良くない?

いい話。でもこれを解決するのはSingletonではなく、現在のゲームのコンテキストに対して一個あるだけのもの、とかで良いはず。


というかMonoBehaviourを拡張するな。あれはこう、、色々な用途を持つ、UnityとC#コード(というか開発者がやりたいこと全て)をつなぐブリッジ部分だ。

みたいなことを思うことは割とあるけど、まあ人の数だけ正義があるので、正しさ~みたいな話はしない。ほら、人の正義とかどうでもいいじゃないですか。



それでも避けられない、みんなが欲しい、Unity + Singletonに求められるもの

MainThreadDispatcher

俺は!! ここから!! メインスレッドに!! 何かを投げ込みたい!!!


例えばiOSとかだとそういうの簡単にできるんだ。本当にどこからでも簡単に。

でもUnityにはそういうのないんで。誰かが作って、それをグローバルにおいて、っていうのがよくある。


UniRxとかな。


4.6が使えるようになる + SynchronizationContextがあるじゃん! っていうのははい、ありますが、

どこかで取得してグローバルにしないといけないのですよね。はい。 


俺は無手でメインスレッドに放り込むようなものが標準でなんもせんで欲しいのだよ。(iOSとかそのへんで存在してて便利)


オーディオエンジン

オーディオの再生制約にメインスレッド必須があるせいで、どこかのオーディオエンジン使う以外だとシングルトン作って済ませてしまうことが多い。


wrote 2018/07/29 12:18:54

ReplayKitWrapper


概要

Unity2017を使っているプロジェクトで、iOS11上で動かす際にUnityのReplayKitを使うとクラッシュする。

そのため用意した。


あとUnity2018でもクラッシュはしないもののiPhoneXで画面レイアウトがクソダサになるという辛いところがあり、

このプラグインは2018でもいい感じのビューを提供してくれる。


ReplayKitWrapper

https://github.com/sassembla/ReplayKitWrapper



わあでけえ、、

IMG_1722.PNG

wrote 2018/07/27 1:58:49

Suba - swiftコードを書くとそれをUnityから叩けるようにするやつ


概要

Suba(すば) というツールキットを作っている。


Suba

https://github.com/sassembla/Suba


Unity + iOSで、swiftでプラグイン書きたいじゃん? そんでそれをUnity C#から使いたいじゃん?

というわけで作ってみた。


swiftコードを書く -> ラッパーとなるC#コードとかもろもろが生成される -> 使える という感じ。



欠点

呼び出したいswift関数に @objc アトリビュートをつける必要がある

プロトコルを使うクラスは 必ず private class などを使って定義する(iOSのObj-C -> swiftを呼ぶ仕組みがあって、それがprotocol定義と相性が悪い)

iPhoneXのSafeArea対応をコードで行う必要がある。空のwindow作ったりすると楽。(Unityにはそういうのないので)



利点

swiftでコード書くとC#から動かせるようになる



コード生成部分がひと段落したら追記する。

wrote 2018/07/24 9:44:45

Real World Addressables(WIP)


概要

AddressableAssetsSystem(AAS)の機構を使いたいので、まず基本的にどんな使い勝手なのか、また、こんなことがしたい時どこをいじればいいのか、などを書いていく。

根本的にAAS自体がWIPなのだが、バージョンが変わってもどこを変えてどうすればいいのか、はあんま変わらんと思って書いている。(この行を書いたときはかなり楽天的だった。)



version

ver 0.1.2で書いてる。2018.2にそのまま入れると、AddressablesのGUIを開いたときにGUI生成できないエラーが出る。

で、0.0.27でいっぺんaddressableAssetのデータを作成 -> 0.1.2にアップデートすると、問題なく動く。WIP。



基本的な使い方

日本語だとここがわかりやすい

「Addressable Assets Systemを完全に理解する」

https://qiita.com/k7a/items/b4fd298bcb64dc968ad1


使用手順を超簡単に書くと、

1.Unity Editor上でカタログを作成する

2.ゲーム起動時に自動的にカタログを取得してくるので、ゲーム中でLoadAsset<T>とかやると1で作成したリソースが取得できる。

というような感じになる。



AASの機構の概念

UnityのAssetBundle(AB)は複数のAssetを一個のファイルに固めてダウンロードしやすくしたようなものなのだけれど、

AddressablesはABのビルド処理やロード処理を行う機構となっている。


ABの操作に関してかなり完璧に隠蔽できているため、ABについての専門的な知識がなくても扱えるようになっている。


つまり開発者はABについて理解するかわりに、AASについて理解をすれば、AssetBundleでできることを簡単に扱えるようになったと言えるような言えないような。

まあ理解する対象が変わっただけなんだけど、根底にあるのはABを生成、ロードする機構なので、AASの構造に不都合があったらもっと理解して書き換えていけばいいのだ、とかそんな感じ。


このへんは、HTTPを理解するためにTCPを理解する必要はない、みたいな関係性に似ていると思う(適当)



実装、構成、モード

AASは表層にあるAddressablesと、根底にあるResourceManagerの2段構成になっている。


基本的にはUnityEditor上から、コンパイル時に

「どんな外部リソースがあるか」

「外部リソースをどんな名前でロード可能にするか」

「外部リソースをどんなキーワードでグループ化するか」

「その外部リソースをどこからロードするか」


などの情報を集めておき、それらを入れた「カタログ」と呼ばれるデータベース = ファイルを生成する。


カタログには上記の情報がセットされており、ゲーム起動時にAASが自動的にカタログの取得を行う



外部リソースをどこからロードするか、については入り組んでいて、

AssetをAASのウィンドウに登録すると、Assetは必ずどこか一つの Address Groupというものに含まれるようになる。

このAddress Groupは、含まれるAssetをどのように扱うか、というのを決めるための集合で、次のような設定を行うことができる。

・Groupに含まれる全てのAssetをどんな感じにAssetBundle化( = 1ファイル化)するか

・どこから取得するか(Local or Remote)

・ビルドしたABをどこに吐き出すか


つまり自由なグループ単位でAssetのロード元を指定したりできるんだけど、

えーーっと、まあ大規模になったら手でやるのは無理だと思うんで観賞用かなあと。AssetGraphとかでいじれるようになるのを期待する。


話を戻して、起動時のカタログ取得以降は、AASは開発者のリソース取得リクエストに対して、


リクエストをキーとしてカタログ検索

-> 対象をどうロードするかなどの情報を取得

-> 実際にリソースを取得して開発者に返す


などの処理を行なっている。



先に書いとく、AASの超WIPなところ

多分この項が一番有用な話だと思う。なんらかの進捗があると安心して使えるようになる。



カタログ取得(自動)(強制)(毎回)に失敗すると死ぬ

リソースをWebから取得する設定の場合(というかAASの使用例の99%くらいそうだと思うが)、起動時にカタログをサーバから取得する。

この際、ひたすら早いタイミングでカタログ取得の通信が走り、その通信に失敗した場合、AASの機構は死ぬ。


失敗したらどうなる? 機構の初期化が途中で終わる。おま、、WIP、、、


このカタログ取得通信を任意のタイミングに変更することができるか?と言われればNoで、これはAASの起動 -> 通信機構にRuntimeInitializeOnLoadMethodアトリビュートが付いているため。

通信環境チェックやリトライすらないっぽいのでヤバい。Playerの起動時の不安定さもあいまって、エディタ + Packedプレイモードだとだいたい50%くらいの確率で失敗する。


また、これは大変ダサいが、エラーになってしまった後で手動でAASを再起動できるかというとNoで、AASのInitializeResourceManagerはprivate staticで定義されている。はい。



おまけで、カタログ取得のベースurlは変更不可能なApplication.dataPath下に置かれるため、ゲームのコンパイル時に完全固定となる。

これは例えば、ゲームの起動時にユーザーのリージョンを見て、一番近いリージョンのCDNから落とさせるためにurlを変更する、みたいな芸当ができないことを意味する。


あとリソース取得時に認証を云々も無理。速すぎる。ヒールアンドトゥの兄貴かよ。


今後このへんも可換になってほしい、、、

Unity IAPがかなりまともなハンドリングを提供してくれているので、最終的には期待している(あと大人なのでコントリビュートすればいいと思っている)



エラーの原因がわからない

WIPなのであれなんだけど、例えばLoadAsset<T> (string assetName) は、UnityではおなじみなasyncOperationを返してくる。

これが、例えばネットワークが死んでて失敗したり、指定したassetNameが違ったりして失敗するんだけど、

現在の段階では「成功か失敗かはわかる」が、「なんで失敗したのか」がわからない。


ざっくりいうとエラー情報が一切ない。


LoadAsset系の処理の完了を待つには、Completedイベントが着火するか、asyncOpそれ自体をisDoneになるまで回して、Statusを見ればいい。

Statusは、成功時にはSucceeded、失敗時にはFailedというenumを返して来る。


IsDoneは、LoadAssetが成功しても失敗してもtrueになる。

OperationExceptionはどんな失敗でもnullのまま。お前何。

IsValidは、成功しても失敗してもtrueが返ってくる。お前も何。


Status以外の他のパラメータは全く当てにならない。WIPなので、今後ちゃんと何か入るかもしれないが、全体のエラーを網羅したenumとかがないと大変な目に合うと思う。


エラーの内容がわからないので、プレイヤー = ゲームを遊ぶ人に対してどんな情報を与えればいいかがさっぱりわからん。

というかエラーに対してどんな処理走らせればいいかもわからんのよな。



ありえる厄介なエラーとしては、

・プレイヤーが平和にゲームを遊んでいるタイミングで

・開発者がCDN上のデータを更新して

・古いカタログ情報を元にプレイヤーがリソースにアクセスしてきて

・古いカタログ情報だと最新のリソースが取得できずに死ぬ

みたいなのとかはよくある話で。

こういうケースだと、「持っているカタログが古いです。最新のカタログを取得中..」とか表示を出して、プレイヤーを待たせている間にカタログを取得、再度落とし直す、とかをすればいいんだけど、

そのためには割と精緻なエラー情報が必要で。


例えば今使っているAssetに更新があったりなかったりとかでどこまで戻ればいいかが変わるし、

今は大事な画面なんでプレイヤーをこのまま遊ばせたい、戻らせたくない、みたいな選択だって立派に必要な選択肢だ。


エラー判定について一応確認してみたけど、Addressablesのテストの中だと、StatusではなくResultがnullではなければOK、というような判定をしていた。

そのうちOperationExceptionがマトモに入るんだと思う。


で、まあ、それに沿ったハンドリングをすることになるんだけど。



WIPのまとめとこのあとの記事の前提

以上を踏まえ、これ以降の記事は

・なんかいい感じのタイミングでカタログ取得が済んでいる

・カタログの内容、Web上に置いてあるリソースについては一点の非もなく、いつでもアクセスできる

・LoadAsset書く側が、Loadしたいアセットの名前をタイポするなどのミスを100%しない

という前提に立つものとする。



現状のAASはかなりセンシティブで、この前提を守らないと動かない。WIPだし。

まあダメだったらコントリビュートすればいいので!



どこをどう交換すれば何ができるようになるのか

起動タイミングのいろいろがAASの初期化コードにハードコーディングされてることは置いといて、

次のようなことをしたい場合、どこをどう変えれば(可換なプロバイダを作れば)いいのかをまとめていく。



(まだひみつ)(というかエラー処理考えると将来にわたって変わらないはずがない確信が得られたのでとてもつらい)




以下おまけ


シーンとかってLoadできるの?

できる。モードも指定できる。

var sceneLoading = Addressables.LoadScene("NextScene", LoadSceneMode.Additive);

sceneLoading.Completed += op =>

{

    Debug.Log("op is succeeded?:" + op.Status);

};



AssetをダウンロードするURLってどこに入ってんの?

PackedモードであればStreamingAssetsにセッティング情報を保持している。

それ以外のモードであれば、"dataPath/Library/Addressables_settings_" + mode + ".json" にセッティング情報を保持している。


これはカタログのurlも同じで、そちらは "dataPath/Library/Addressables_catalog_" + mode + ".json" に保存されている。


この部分はreadonlyなんで、アプリケーションを更新しないと更新されなそう。

データの更新は実機ビルド時、プレイボタンを押した時の2つ。


動的に書き換える方法はあるんだろうか。

-> dataPathはreadonlyなんで、リビルド以外なさそう。UnityEditorでAddressable Assetの設定を行う時点で覚悟を決めるか、サーバ側でURLを捻じ曲げるか。



LoadAssetとかのCompletedが着火するタイミングはLateUpdate

Completedイベントが着火するのはLateUpdateに固定されている。知らないと地味にハマりそう。


これは、asyncOpの監視をLateUpdateメソッドよりも実行順が前なメソッド内(Updateとか)に置いた場合、

その発火はCompletedの発生よりも1f遅れる = 次のフレームになる、ということを意味している。


例えば次のようなコードの実行順になる。

IEnumerator Start()

{

    // この時点で0 frame

    var prefabLoad = Addressables.LoadAsset<Material>("Mat");

    prefabLoad.Completed += op =>

    {

        // ここが発生するのが0 frame(のLateUpdate)

    };


    while (!prefabLoad.IsDone)

    {

        yield return null;

    }


    // ここにこれるのが1 frame !

}


太字の部分だけ見るとわかりやすいと思う。

Completedが着火するのはLateUpdateなのだ。なので、処理が十分に早いと同じフレームの別メソッド呼び出しで完了する可能性がある。


asyncOpを監視するスクリプトのexecution orderを0(デフォルト)にしてLateUpdate関数内でasyncOpを監視すると、Completedの着火よりも速くイベントを認識することは可能。

まあだから何って感じなんだけど。



LateUpdateで実行すると同じフレームで返ってくるんだろうか?

-> 次のフレームのLateUpdateで返ってきた。必ず非同期。



こんなことしたい、の書き方をテストから探す

ドキュメント見ても、「実際こういうのどう書いたらいいんだろう?」みたいな疑問は出てくる。そりゃやりたいことが全部載ってるわけじゃないからね。

そういう時はテストを見てみるといいかもしれない。

UnityのPackagesに入っているものには見た感じすべてテストが含まれており、それらのテストをUnity上で動かすのは割と簡単にできる。

スクリーンショット 2018-07-13 14.13.05.png


1. UnityのProjectウィンドウ > Packages > テストを走らせたいパッケージを選択 > Reveal in Finder 

2. 表示されたフォルダをデスクトップとかにコピー

3. 新規プロジェクトを作成

4. 新規プロジェクトのAssetsフォルダに、2でコピーしたフォルダを放り込む

5. プロジェクトを開くと、テストがあるパッケージであればそのテストがTest Runnerに表示される。


5の時点でコンパイルエラーが出る場合、おそらく持ってきたパッケージ自体が依存している別パッケージがある。

2で開いたフォルダからなんとなく「これかな?」って持ってくるとうまく行ったりする。


新規プロジェクトを作るのはオススメ。なぜオススメかというと、へんなファイルがあるところにパッケージを持っていくとものすごいカオスが出来上がってしまうため。



さて、ここまでしたパッケージのテストが通るのか?というと、前提条件が異なる場合はもちろんエラーが出るので動かないケースも多いが、

自分が見た範囲だと大体動いている気がする。特にResourceManagerのテストは凄まじい。


扱う対象のAssetをこの一件のテストのためだけにコード経由でimportし、テストが終わる頃にはUnityのAssetDatabaseから消す、ということをやっている。

ぶっちゃけすごい。こういうテストすごく大事なので参考にしたい。


wrote 2018/07/10 10:43:10

Protobuf for Unity続編


概要

https://github.com/google/protobuf/pull/4559

要はiOS/IL2CPPでのRefrelction.Emitが失敗すると。



2018年4月、CSharp版のprptobufのライブラリにこんなプルリクがマージされていた。

https://github.com/google/protobuf/tree/master/csharp



いいね!これでdllつかえるんじゃね?

-> 使えた。


コードとかをあれこれやらないでもいけるようになっていた。いいぞ。



wrote 2018/06/29 10:49:00

AssetGraph1.3から1.4へのアップグレード


概要

軽い気持ちでアプデしたらassetファイルに互換性がなくて困った。

こんな時のために1.3にはjson export機構が入っていて、

じゃあ1.3でexportしたjsonを1.4にインポートすれば、、!

ってやったらそっちは軽微な罠があったんで回避した。



内容

1.3で出力したjson1.4に食わせると、インポート直後のグラフがnullを含んでいて吹っ飛ぶ。

これは、json -> グラフオブジェクト への変換部分で、AG1.4では含まれていないクラス情報が存在するため。


具体的にいうと

UnityEngine.AssetBundles.GraphTool

っていうnamespaceが1.3 → 1.4で滅んで、


UnityEngine.AssetGraph

に変わっているため。


AGからexportしたファイルに型情報の記載があり、

その情報をもとにリフレクションでインスタンスを生成するんだけど、その部分のサポートが特にないため、

1.3で作ったものを1.4に持って来ると滅ぶ。



今後

プルリク出しておいたんでその、はい。

今すぐなんとかしたい人は、

1.3から出力したjsonの中でUnityEngine.AssetBundles.GraphToolって書いてあるところを

全てUnityEngine.AssetGraphに置換してから1.4にimportすると助かる。




wrote 2018/06/11 14:46:41

テスト完全に理解 #1 Done


概要

こんなイベントがあって喋るなどしていた。


「Unityテスト完全に理解した」

https://connpass.com/event/88124/

タイトルは、Unite2018のアフターパーティーで 強火で進めの人 に、

「なんかテストの話とかしようと思うんすけどどんなタイトルがいいっすかねえ」って相談したら、

「完全に理解したとかどうですか」って即答されたんでこういう感じになった。


会場はmixiさん。ものすげー助かった。


最初50人で募集開始するも、瞬殺されて80くらいまで伸び、ヤバくね? 増やせるんですか?! みたいな舞台裏トークののち

90人まで拡張され、それも瞬殺されてしまうなどしていた。


最終的には150人まで並んでしまったので、こう、はい、、そこまでニーズがあるとは。

みなさん苦労されてるんですね(笑顔


講演死霊

このへんにまとまってはい。

https://connpass.com/event/88124/presentation/



自分の話

Unityでのテストのコード紹介、オススメのテスト方法の話とかをしていた。

Tシャツ芸やろうかな~って思ってたんだけど舞い上がってて忘れてた。


懇親会で自分のE2E系の資料を見た人がことごとく絶句してたのが大変よかった。


質疑応答みたいな時間を持つともうちょっと良かったね~~。 すまない。


自分が勉強会行った時にまずスピーカーに聞きに行く、みたいなムーブやってるくせに、

話す側に回るとそういうの忘れてしまうのだった。


次はAsk the speakerありでやりたい。



完全理解

完全ではないが、UnityTestについて自分が実装した色々を見ていて、

「あれ、UnityTestってこれ、テストというより短編ゲーム起動機では?」

みたいな認識を得られたのがとても良かった。


タイミングよく @z_zabaglione さんに、ECSのリポジトリとかにはテストが書いてあるんですよ みたいな話を聞けて、


EntityComponentSystemSamples

https://github.com/Unity-Technologies/EntityComponentSystemSamples


んで実際に書いてあるテストが


・buildSettingsにセットされている全てのシーンを順に読み出して

・各1秒待って

・Unexpectedなログが出てなかったらセーフ!

https://github.com/Unity-Technologies/EntityComponentSystemSamples/blob/master/Samples/Assets/Tests/Playmode/SceneLoadingTests.cs#L20


っていう、


複数のシーンでデモを作って、それらがぶっ壊れてLogErrorが出たら検知できる、みたいなテストだった。


そうそう、こういうのでもいいんだよね。


ログエラー出たらUnityTestってFailとして停止するからその、なんだろう、面白いよね(知られていなさそうだが言い忘れた知識



謝辞

一緒にスピーカーとなってくれた もんりぃ先生 さん、スピーカー兼会場提供を手引きしてくれた いも さん、

当日運営からなにからなにまで頼りっきりだったスーパーイベント運営完全理解者 青木とと さん、

会場提供していただいた株式会社mixiさん、


大変ありがとうございました。



wrote 2018/06/07 21:41:46

AVAudioSessionCategoryPlayAndRecordと接続機器ごとの音量


概要

ハマっていたのではい。

このモードだと出力される音量に制限がかかる。

その制限がいろいろ接続機器で変わるね~という話。



要件

1.マイクを使って録音したい

→AVAudioSessionに対して AVAudioSessionCategoryPlayAndRecord をセットする

これは、Unityでmicrophoneクラスを使ってRecordとかやった場合も同じ挙動になる。


このカテゴリーの最中、iOSから出力されるオーディオは、最大音量にしてだいたい70%カットくらいのキャップをセットされる。

理屈としてはまあそりゃそうで、録音してるはずなんでスピーカーから変な音出さんほうがええやろ、という。

この状態で音が出るのは録音と同時に音が出る、プレイバック用途っぽい。


で、この状態だと、どんな出力装置が「どう」iPhoneに接続されているかで音量に対するキャップの挙動が変わる。


2.録音した音を別の端末で再生したい

したかった。1で録音、そんで別端末で再生。



まずは、1の、どんな出力装置が「どう」AVAudioSessionCategoryPlayAndRecord カテゴリ中のiPhoneに接続されているかで、

音量に対するキャップの挙動が変わる という話から。


接続なんもなし

iPhoneに特別なんの出力装置も接続しない場合、iPhoneのスピーカーから出力される音量は、

AVAudioSessionのカテゴリの影響 = 音量キャップ を受ける。



スピーカー、ヘッドフォンがプラグで刺されている場合

キャップなしの音量でサウンドが再生される。

・録音中な可能性もあるけど、別に出力装置をつないでそっちで音がでるくらいええやろ

・オーディオアウトの処理に対してそのまま音を出す

みたいな考慮がされてる気がする。



スピーカー、ヘッドフォンが、Lightning端子、無線で接続されている場合

面白いのは、、これだ、、!!


LightningかBluetoothでヘッドフォンをつなぐ場合、そのスピーカー、ヘッドフォンから出る音量は、

AVAudioSessionのカテゴリの影響 = 音量キャップ を受ける。


なぜなのか。



ドキュメント

https://developer.apple.com/documentation/avfoundation/avaudiosessioncategoryplayandrecord


特にそういう無線接続した場合のみうんぬんみたいなデフォルト挙動については特に書いてない。


AVAudioSessionCategoryOptionDefaultToSpeaker とかの、AVAudioSessionCategoryPlayAndRecordカテゴリの時だけ有効なオプションを追っていくと把握できそう。

今回はデフォルト(オプションなし)だったので、この挙動だったぽい。


あとはまーー、、もう音声出力のプラグって新しいiPhone機種にはないので、無線出力も既存スピーカーといっしょくたに扱おう、みたいなのがデフォルトなのかも。


要件1のまとめ

・AVAudioSessionCategoryPlayAndRecord カテゴリだと、音量にキャップがつく

・接続機器が有線か無線かでキャップの処理に差がでる

有線プラグで接続して不意に爆音が出て死にかけた。



つづいて要件2。



2.録音した音を別の端末で再生したい

ここでは、AVAudioSessionCategoryPlayAndRecord カテゴリで録音した音をファイルとかに吐き出して、

別端末で受け取って再生する、みたいなことをする。


で、

当然だけど、AVAudioSessionCategoryPlayAndRecord で録音した「音」それ自体には、同カテゴリ特有のキャップはかかっていない。


再生側でばふつーに録音時の音量で再生される、ということがわかった。


wrote 2018/05/26 13:52:45

Addressable AssetとAutoya/AssetBundleモジュールの比較


概要

材料揃ったんで書く。

先に書いておくと、Addressable AssetはC#で書かれたモジュール、

Autiya/AssetBundleモジュールもC#で書かれたものなので、

どちらもコードをいじることで機能の追加や削除が可能になっている。


ここでは、デフォルトを比較する。



Addressableを生成してAssetに対するアンカーとして使う

Addressableにしかない。



AssetBundleの情報の集合をリストとして扱う

双方OK

リストのダウンロード -> 使いたいAssetを含んでいるAssetBundleを見つけてDL、キャッシュして展開、、など。



複数のAssetBundleリストを使う

Autoyaでは複数のリストを同時に扱うことができる。


機能リクエストはしておいたので、Addressableでも叶うかも。



アプリケーション動作中にAssetBundleのリストを更新する

AutoyaではAppの動作中に、サーバから新バージョンのAssetBundleリストを取得、更新することができる。

現在使用中のAssetを含んだAssetBundleが更新されたかどうか、などもサーバ主導でハンドリングを行える。


Addressableでは、起動時に一回だけリストを更新することができる。



AssetBundleのPreload

Preloadは、AssetBundleを展開することなく、DLだけを行う処理。

双方OK



Preloadの並列化

複数のPreloadを並列に行えるかどうか。

Autoyaでは並列数を指定して実行できる。


機能リクエストはしておいたので、Addressableでも叶うかも。



バージョンの付与

Autoyaではリリース済みのAssetBundleに対して、そのリストに特定のバージョン値をセットすることができる。

これで、例えばクライアントが今どんなバージョンのAssetを触っているか、とかが把握できる。


エラー処理

Autoyaでは、iOS/Androidなどのモバイルでの通信エラーやら何やらをメチャクチャ丁寧にハンドリングしている。

Addressableはデフォルトではそういうのなさそう(カスタマイズ前提)っぽいので、この辺は頑張って欲しい。



補足

Addressable Asset系のすごいところは、

・上記の機能は標準では入ってないけど、リスト作成(Addressableコンパイル) -> 起動時リスト取得 -> Assetの指定をAddressable Assetで行う

というフローが整っているところ。


特にフローの整理っぷりは素晴らしい。

いままではフローを実装するところから始めていたのが、このフローのどこに何載せよう、みたいな感じに簡略化できる。


Autoya/AssetBundleモジュールとほとんど同じフローなのも、俺的には良い。


もしこれが完成したら、自分はAutoya側のAssetBundleの機構をメンテしなくてよくなるのだ!!



wrote 2018/05/18 14:18:20

Unite2018.day3


新機能Shader Graphを使えばプログラミング無しにシェーダーが作れるようになります!

Create > Shader > ShaderGraph >  とかでサンプルが出る


右上のプロパティブラックボード、というところでプロパティを足せる。

-> それをグラフ上にD&Dでノードとして配置できる。パラメータを足せる。


具体的に作ってみる


ディゾルブ

・アルファカットアウトで

・際が光る


cutoff値よりも小さな部分を透明にする、

で、濃淡がある画像に対して行ったりすると、その形に抜けていく。

かつ、際の色を発光にする。


SampleTex2Dを作って、

石像に使われるノーマルマップをPBR Masterノードにセット

モデルは右下のほうでCustomなモデルにセットできる。


SampleNoiseを作って、MasterのAlphaに突っ込む


Vector1パラメータノードを作って、MasterのAlphaClipに突っ込む

-> この値をいじると、透明度が変わる。


閾値、Threatholdは、Stepノードを使う。

あるedge値をセットすると、流れ込んでくるものによって0か1を返す。


Stepに対してNoiseをインプット値として接続、Vector1ノードをedgeとしてセット

こうすることで、V1をedgeとしてインプット値を0か1にできる。


Timeノードを使う

ゲーム開始からの秒を返してくる

Fractionノードを使う

小数点以下を抜き出す


Time -> Fractionで反復Animationが作れる。

Fraction -> V1へと接続し、時間で変化する反復要素を組み込む。


プロバティブラックボードにカラーを新規作成し、そこからノードを作成する。


Multiplyノードを足して、カラー -> Mul -> Masterに接続すると、Untiyのプロパティからエッジのカラーをセットすることができる。


ゲージ

グラデーション素材とスレッショルドの合成で表現


・グラデーション素材を適当に作る

・Unlit Graphで作成(ライトの影響受けなくていいので

・半透明を使うので、Unlit Masterノードの設定を変更、 Opaque -> Transparent


円形ゲージに対して、中心から直線を引いてぐるりとグラデーションを回したようなグラデーションを用意する。

Tex2D

Step

V1

を用意、


V1 -> Stepのedge、

Tex2D -> Stepの値

とやって、

Remap

in(min ~ max)に入ったものを、out(min ~ max)の範囲で出力さっるよう一時変換するノード。

0 - 1で入れたものを、1-0にすることで入力を反転する。


Stepだと値がバッチリ切れてしまって、これで値を作るとテクスチャがジャギってしまう。

-> SmoothStep ノードを使って書き換え!

ゲージのエッジがいい感じに滑らかになった


ゲージの画像をmulノードで追加する。


2つの値を補完したり、アルファブレンディングするのはlerpノードを使うといい感じ。



荒ぶるテレビ

PBRシェーダ、

SampleTex2Dで対象の画像をインプット

ライトの色を黒にして無効化


Sinノード

Sin波を使って、横軸に入るしまを作ろう。


Splitノード

ベクトルを成分に分解する

ついとなるCombineノードは、A,R,G,Bなどからベクトルを作り出す。


Sin波をMulで200倍し、


Saturateノードで、-1 ~ 1のSinを、0 ~ 1に変換できる。


UVAnimationさせてみよう。

Time -> Mul -> Addを接続する。



Time -> GradientNoise -> 横にぶれるエフェクト、とやって、「ランダムな時間によってぶれる」みたいなのを実現する。



補足情報

今日の例はgithubにあるよ~~

https://github.com/keijiro/ShaderGraphExamples



CustomNodeの実装

既存のNodeを組み合わせてCustomNodeを作り出せる。なるほど。



スクリプトによるTimelineがっつり拡張入門


おさらい

・いろんなフィールドをコード無しで書き換え可能。

・パラメータさえMonoBehaviourであれば扱える。

Timeline(Playable)

PlayableDirectorComponent に入っている。


Track

Bindingしたものを扱う。

Cllipを含む

Clip

時間指定した効果



AnimationTrack

GOのパラメータをコントロールしたい時には使える。

例えばPostEffectとか、GOではないものはコントロールできない。スクリプトを書く必要がある。


次のような選択肢がある

1.AnimationTrack + MonoBehaviour

2.ControlTrack

3.CustomPlayable



1.AnimationTrack + MonoBehaviour

一番簡単、MonoBeで扱えばいい。

Updateとかでいじる。



2.ControlTrack

MonoBehaviour とITimeControl を実装する

Clipの開始、終了、再生中がわかればいい、という場合に有用。


OnControlTimeStart, SetTime(double) とかがある。

Clipの最大長は取れないので、こう、はい。事前に知っている必要がある。



3.CustomPlayable

専用トラックの定義。

Behaviour

クリップごと


Mixer

トラックごと


Mixerのほうが使いやすい。

・実時間を扱っているせいで、Behだと処理落ちで終了までのプロセス全てが動くわけではない、という可能性がある

Trackの拡張

BindingType(型)

Trackの色

TrackClipType(コンテキストメニューに現れるクリップのタイプ、複数貼るのが可能


TrackAssetを拡張、


override Playable CreateTrackMixer

Playable(今回はMixer)を生成する。


var mixer = ~して、

(この時点でmixerをこのコンテキストで保持しておくと、後からいじれるので良い、らしい。)

return mixer;


override void GatherProperties

Clipの(?)終了時にプロパティを戻す。


Mixer

トラック全てに対してイベントを発生させる。

全フレーム、Processメソッドの呼び出しが発生する。


Recordしたい、Timeline上でカーブ入れたい、、、

Clip内にBehaviourを持ち、bh内にパラメータを移動する。

Behaviour拡張はかならずSerializableをつける。

中のパラメータもpublicだったりSerializeFieldで定義する。

すると、それらは追跡できるようになる。


これらのClip内の物体は、メソッドを持たせず、全体を見通せるMixer上から編集するスタイルがいいと思う、みたいな。



さらなるスクリプト

AEからコンバートして再生!というのをやってみる。

MovieProxyPluginを使って、連番アニメーション限定、なるほど!!


あとでデータ見てみよ。



運営中コンテンツにおける大型アップデート成功のための考え方とUnity最適化手法

話題の大半が、ひたすら実践的かつ、「えっそれを決断してやれる組織あるんすか、、マジすか、、」みたいな顔になることが多かった。

シェーダ、グラフィックを大幅更新した話

リム、スペキュラ、環境マップは、キャラクターものを作る上で絵がダイレクトに影響を受けやすく、効果が高かった。

パラメータテクスチャを用意、テクスチャを用意してRGBで強度を調整する、という感じにした。

Unityの法線は1つしか持てない -> FBXからインポートすることもできない。

で、FBXを2つ作って、2つの法線をもつ -> 自前インポータを書いて2つの法線を持つデータにする!と。


CGFXをMayaとUnityで共有することで、プレビューを可能にした

すごーい!



Androidでのテクスチャのバンディング対策

ETC2 Normal使うと、0.5秒の圧縮時間と、バンドが出ない映像が得られることがわかった。

ETC2もっと早く使わなかった理由は?

・騎手が対応しているかどうかの判別手段がなかった

・ないところで使うと6倍のメモリをああああ

・Unityのバグもあった



並列AssetBundleビルド

manifestファイルさえあればそのビルドは発生しない(!)という特性を使い、

特定の単位でビルド対象を切って、manifestを共有していけば、新規や更新があった部分だけが作成される。

-> これめっちゃ素敵なのでパクろうと思う。

Unityキャッシュサーバ高速化

キャッシュのサイズを500GBにして対応、30分 -> 7分 とかになった。MacProを使った。



まとめの近所

まとめで、「誰が作ったものにもバグはあります、もちろんUnityにも。でもやっていきましょう」みたいな話があって、

ひたすらうなづいていた。



『CARAVAN STORIES』のアセットバンドル事例

めちゃくちゃ綺麗な絵の素敵なゲーム。


正規表現を駆使してResources -> AssetBundle ,,みたいな探索

これって開発中のみ?

->常に実用

すごいパワフル、、Resourcesのラッパ作ってそこでだけ行えばいいのでは感があるけど、ものすごい機構。



Unloadのくだり

2秒で自動unloadしてる

メモリに保持しておくのが惜しいのか~。なるほど。

それであれば、辞書を作ってそこにInstantiateしたのを持っておけば、即解放しちゃっていいのでは?

-> ABManagerがそんな感じの実装を持っているらしい。


ただ、音データとかをコピーなしで鳴らしていると、Unloadしたときに同時に消えちゃうはずで、確かにそんな感じになったというのが発表にあった。


variantのくだり

使わないほうがいい、Yes。ほんとにそれ。



AssetBundleNameを使ってると困るところがある

-> タイミング的に、Unityの負荷が高いところで使うとよく失敗してた気がする。

-> 後続のverでは滅びていた気がする。AssetGraphとかである程度できると思うけれど。



IDCFのCDNだと問題が出る

別にAWSでも発生するんでは、みたいな。クエリつけようねみたいな話だった。



スクリプタブルレンダーパイプライン入門

いろんなゲームのレベルがあるよね


Motivation

Unityのレンダリングをblackboxにしたくない、

カスタマイズの自由を提供したい。

APIs

Built-In Render Pipeline(will be dep)

既存


Lightweight(beta)

MobileとXR向け、一つの光源、


HighDefinition(preview)

ハイエンドPC向け


Custom

カスタム!!



どこから始めようか

Tips:ライトを切るとBatchやTrisがすごく減る

SRPの使い始め。


新規プロジェクト作成 > 作成ウィンドウでLWRPとかを選択したり、packageManagerから最新版をロードできる。

スクリーンショット 2018-05-09 17.03.12.png

これらはLWRPのHigh,Middle, Lowとか。あとPostProessingがついてくる。

LWRPはそれぞれ設定の重量が違う状態のAsset(ScriptableRenderPipelineアセット)

このAssetを、

Project Settings > Graphics > 

スクリーンショット 2018-05-09 16.51.14.png


GraphicsSettingsのところに適当なLWRPAssetをセットすると、画面に対するパイプラインが変更される。

スクリーンショット 2018-05-09 16.51.26.png


LWRPでのライト

メイン一個のみがサポートされている。

パフォーマンスよさげ。


Rendering設定 > PixelLight でPixelLightの数を調整できる。

これらのライトは影を落とさない。ので、描画計算に影響を与えない。

最大8。

スクリーンショット 2018-05-09 17.03.18.png



DebugWindow

実行時に描画オプションをいじれる、、らしいがよくわからんかった。今度講演資料みよう。



CustomRenderPipelineについて

参考になるものといえば!みたいな話題


けいじろうさんのRetro3DPipeline

https://github.com/keijiro/Retro3DPipeline


あとgithubでScriptabkeRenderPipeline自体が公開されている。

https://github.com/Unity-Technologies/ScriptableRenderPipeline




そろそろ楽がしたい!新アセットバンドルワークフロー&リソースマネージャー詳細解説

・ScriptableBuildPipelineで、ビルド時などのサポートができる。すべてC#製。

・previewがリリースされている。0.0.22-preview

・エディタでのPlay時にABの更新をやってくれる


AssetReference

prefabみたいなもの。参照になるので、打ち間違いとかはない。



読み出し方

・AssetReferenceオブジェクトをインスペクタからセットしたりする。

・annotationでの型、ラベル(by Addressablesツール)指定で、扱うAssetの指定を行うことが可能。

・参照カウント方式なんで、消すときはReleaseを行う。

たぶん無視して種類全消しとかもできるのでは?


・同じロジックのままでDL元を変更できる。

・どこから取得するか、というのを、グループという単位で指定できる。

1.Local

2.Remote

3.Advanced


・ContentsCatalog、という全てのアドレス、ラベル、グループの情報が入ったファイルを生成する。json。

・ラベルによる事前ロードを行うことができる。

AutoyaでいうPreload。これ動的に生成できないかな、、

特定のラベルがついているAssetをすべて取得することができる。素晴らしい。


・Profile 設定集

Devとか切り替えるよね、ってやつ。素晴らしい。変数の列挙。


・PlayMode 設定

開発の状況に合わせてデータのロード方法を一括変更するパイプライン処理が選べる。

1.Fast(デフォルト、AssetDatabaseを見に行く

2.Virtual(ABに似せたロード経路を使う

3.Packed(ABを使う


・ResourceManagerProfiler

現在ロードされているResourceの情報が把握できる。



AddressableAssetsの役割

起動時処理でグループ設定情報をロード、カタログをロードして、というのをコードでやる。

任意のタイミングでキックできるかな?



ResourceManager

参照関連、寿命の管理を行う。

AsyncOpを返してくるので、ユーザー側で頑張る。


文字列、AssetReferenceを渡すと云々。


カスタマイズ

だいたいすべてのパーツが改造できそう。


たとえばリストであれば、ResLocator、ResProvicerをカスタマイズすればよさげ。


こういったカスタマイズは全て初期化時にセットするんかな。



Q&A

カタログをサーバ側で生json生成してかえしたい(ResLocatorとかをカスタマイズ?

-> カスタマイズできるよ!


カタログに独自値を加えたい、、!(verとかnameとか

-> カスタマイズできるよ!


複数のカタログを扱いたい(管理が楽(見た目関連、データ関連とか

-> appendという形でやるつもりらしい


カタログを更新するタイミングはユーザー定義でいつでもできる?

-> resLocMapをダイレクトに書き換えることで実現できるが、標準ではない


すでにAB使ってるタイミングでそのABを更新した内容のカタログを獲得したらどうなる?

-> 自作

カスタマイズは全て初期化時にセットする?

-> それ

特定のAssetRefの参照カウントを取得することはできる?

-> ない


ReleaseByAssetRef、とかで、特定のAssetRefを元にしてるassetsを一掃できる?

参照カウント管理は自分でやる、が、その機能は面白いんでお話。


RMのエラーハンドリングどうなってる感じ、isErrorみたいなのをやる?

-> いまのところ自作

カタログ更新によって使わなくなったABをどう扱うか

-> いまのところ自作


Preloadの並列数っていじれます?

-> 今はない、おもしろいと思うんでお話。


Preloadに使う引数を外部で生成することは受け付けられる?

ラベルは文字列なんでいける!


感想

紹介のされかた的に、「新しいUnityの仕組み」なのかな=~と思っていたが、実際にはこれはフレームワークなんだな~という理解になった。

・デフォルトかつ固定のフローが存在する。

・複数のパーツから構成され、パーツを自作することでフローに乗ったまま動作を変えられる


うん、これはフレームワークだ。


実際すべてUnity外のC#コードで書かれている、ということで、ほとんどAutoya(自作してるフレームワーク)と同じユースケースを果たせるような予感。

↑のQ&Aで聞いてた部分で、自分でやる、や、今後つくかも、といった部分に関して、Autoyaには含まれていてAddressableにはまだ、という状況なので、


今後めっちゃ使える形になってリリースされるのが待ち遠しい。


wrote 2018/05/09 9:50:48

Unite2018.day2


おもろかった。参加したやつを順に。


誘導ミサイル完全マスター

C#でシミュレータを作るといいかも。動いたらComputeShaderに移動していく。

・生成時にランダムを入れるようにすると便利

並列化された状態でランダムを作ろうとすると大変


・絶対時刻で管理

並列化された状態のアレ。


・爆発距離

当たったところからの距離をとって、音を鳴らすのに使ったりする。



ターゲットにミサイルがぶつかった -> ターゲットに命中を通知する

ComputeBuffer.GetData()でデータをとる。

GPUはそのまま値を返せない。ので、CPUはGPUが値を返すまで停止する。


AsyncGPUReadback

非同期! ただしWindows限定。


描画バウンド

GPUは速いんだけど、どうせ描画がボトルネックになる。

-> カメラの近くのミサイルを移す、距離をとって近いものをN個まで描画する、とか。


Frustam、平面との距離。


位置、距離計算をComputeBufferで扱い、描画する対象を制限する。そのための情報も持つ。




メタルバッファ、トリプルなんで三色、これが綺麗に並んでない場合、綺麗に動いてない。

iPhone6で、ちょうどGetDataのタイミングとして使えるものがあった。安定化はむずかしそう。が、

2fに一回、2フレーム分を取り出すことで効率化した。


-> 実際に使ったAPIはLateUpdate。で、毎フレーム実行すると、GetDataが遅かった時のCPUの荒れを次のフレームでもひきずってしまって辛かった。

ので、2fに一回にすることで、GetDataの荒れを解消できた。

ただ公演でもおっしゃっていたが大道芸なので、iOSとかで使いたい場合、素直に2018.2で出るのを待つのがいいのでは、とのこと。



ユニティちゃんシェーダ2

カラー設定を直接指定できる

-> 好みのカラーを配置できる。


線をくっきり出す、ソーベルカラーフィルタを開発。



暁さん

HighColorMaskを使って、例えば金属だけにSpecularが出るようにしたい。

-> スペキュラマップを使って、光沢が出て欲しい部分だけに色を使った。


フォトショでレイヤ作ってやってるよね -> レイヤもう一枚作る、みたいな。


RimLightMaskについても同様、スカートの中に入らないようにしたり。顔に出ないようにしたり。

-> 顔は、表情で頂点が移動するので、当たらないようにしている。

輪郭のシワとかをリムライトで描くというのにチャレンジしてる。


ローポリだとアウトラインそのままで出すとつらい -> OutlineSamplerで特定の頂点だけお線が出る強さを調整することができる。

頂点カラーを生成 -> テクスチャに焼き出す、とかすると、楽に調整できるよ。



あいんつばいさん

光らせる話。

PostProcessingStackのBloomを設定。

RimlightFeather

テクスチャにしっかりした線を描かずに、金属の表現をする。


ブレードにテクスチャを入れる、カラーマップ上にHDRで加算される。



京野さん

横から見た口をいい感じにマンガチックに出したい


サーフェスピアッシングなら、、

髪の上に眉を描けるなら、口でもできるんじゃない?


UTSではステンシル機能として実装している。

-> できた

が、貫通する問題が出たんで、遮蔽シールドを内側に貼ってDone


-> 法線をUnity上で編集できるんでいけるのでは



アスクザスピーカーで話してみた

Unity 小林さん。

その辺の会社のグラフィッカーさんとかがTAになるルートが欲しい、みたいな話をした。

ワイ「shader関連の知識は沼、一歩踏み込むと深い。UTSとかで入り口は簡単になったな~と思うんだけど」

-> それな

-> 今んとこやり遂げてしまうのは、ひたすら「こういう表現がしたい」みたいな執念が強い人。

-> Unity開発者認定試験でShader関連とかが日本語化されるんで期待してて

Expert Technical Artist:Shading & Effects https://certification.unity.com/products/expert-technical-artist-shading-effects


わーい。

その他だと、「これ以上は今は踏み込まないでいい」みたいなブレーキが欲しい、みたいな話をした。


実践的なパフォーマンス分析と最適化

実機でプロファイルしようね、ゲームの全体とか。

プロファイルツール

Editorに入ってるやつ。実験的にMonoを使って云々。


FrameDebugger

実機のものも観れるんだが。繋げば。はい。


MemoryProfiler

メモリのあれ。

Platform-specific tools

Unityに同梱されてる。



Runtimeメモリがでかすぎる

-> AssetAuditor というツールがあるんで、それを使う。

Read/Write enabledつけると2倍食うかんね

R/WTexEnabled でapplyを行うと、RAM -> GPUへとアップロードする。

mipmapがあると質量が33%増える

カメラとの距離によってテクスチャを変える場合にのみ意味がある。


画像

Crunchcompression ETCが使えるようになっている。が、極端にロードが遅いケースがある?

調査中とのこと。


Animation Curve

Legacyはカーブ数が300よりも小さい場合、有効。

が、Unity Animation Systemを使った方が効果がでるみたいなケースもありそう。


Humanoidは、retargetting と IKを使っている場合に使う。

そうでない場合、Genericを使う。


Animatorコンポーネント

CullingMode ってのがあって、選ぶとスクリーン上にないものをアニメーションしなくなる、みたいなモードがある。

画面に映っていなくても内部的に更新する、みたいなモードもあり。



GameObjectと関連したAnimator

2018から新プロパティができていて、GOが消されても状態を保持できる(GOによらない場所に保持してそう)


で、Animatorの中からGOをKillできるようになる、みたいな。


リモートプロファイリングしたいんじゃ

ask the speakerでいろいろ「こういうことやってるんだけど辛いんだが」みたいな話をさせてもらった。

-> OK、言いたいことはわかった、自分宛にメールしろ

-> した。



パーティクル・マニアクス

LoopUntilReplaced 一定値を超えると、超えた分をトランジションありで消す。

Fade Timeをセットできて、

0 -> 0.7はアルファ、その後の部分はこのシステムでのトランシジョンで使われる。


エフェクトを壁に出すには:

レイキャストから座標変換やると楽そう。


Shape Module

Edgeモードで、メッシュ頂点を起点としてパーティクルを出すことができる。

Ping-pongだと、行ったり来たりする。

頂点の位置で時間を使うような設定もできるようで、頂点が多い箇所でより滑らかに動く。



External Forces Mod

Win限定ぽい? 2018で入った。

影響を与えるパーティクルに対して指定したりできる。


LineRendererEditor

2018.2以降

手で書く -> 頂点減らす、とかができる!

UI Particle

SetVerticesDirty()をするといい感じに描画できるぽい、UI空間でのパーティクルのアップデートとか。


パーティクルのcustimCallingの話

見えるパーティクルだけを動かす、みたいな話。

・CullingGroupを作る

・target.automaticCullingEnabledをチェック

・パーティクルをグループに入れて、範囲指定をセットしてChangeStateを受け止める

・ChangeState内でオンオフを行う


こんなスクリプト

https://gist.github.com/karljj1/aa833be5c2e8a061fb1693ee0d31c915



JobSystemとの統合

高速になるよ!



その最適化、本当に最適ですか!? ~正しい最適化を行うためのテクニック~


iOSでの話

VirtualMemoryの話

VM -> ページに分割されている

Physical > Available by App > Appがallocateしたメモリ、他、、 Clean(readOnly)とDirty(自由にできる)

iOSはheap size限界を明示していないが、だいたい物理の2倍くらい。

iOSはvメモリをコンプレスして物理メモリを確保している。


Unityでの話

テクスチャとかのリソースはNativeメモリにガンガン搭載される。

NativeプラグインはすべてCleanに置かれる。


-> Dirtyメモリを使っているオブジェクトを減らすと良い。


どうやって計算する?



Unity Profiler

デバイス上で動かしていると、Used Total とか書いてあるとこ。


GfxDriverの数値がテクスチャサイズとかの合計(現在描画しているのを除く


何がどのくらいのメモリを食っているのがわかる。


ProfilerからAssets/とかになんか置かれているのが観れるビューがあるぽい。



MemoryProfiler

いつものメモリ見るやつ。



MemoryProfilerExtension

https://github.com/robertoardila/support-unity-memoryprofiler

これは知らなかった。

めっちゃいいのでは!!



Instruments VMTracker

Appのメモリ消費についての解析ツール。

WWDCで紹介動画とかがあったらしい。探してみて見るといいよ、使い方わかるから、とのこと。


Dirtyサイズがゼロの部分は、Cleanな領域にallocateされたものだと判断できる。まあCleanに置かれるのNativePluginとかライブラリとかなのだが。


Instruments Allocation

スタックトレースが見れるんで、そのへんで。すべてVM。

SerializedFile: AssetBundle

il2cpp_codegen_initialize: インスタンスのallocation



VM TrackerとAllocations合わせて

AllocationsのCategoryでVM: Memory *** 255 とかなってたらUnity。

ここまでのツールを組み合わせると、いい感じに答え合わせができそう。



アーティストがUnityでサクッといいビジュアルを作るテクニック講座


PostProcessingStackv2とかを使うよ。

1.適当にものを置きます

2.雨が降ってるんでhazeとかfogとかをセットします

3.PostProcessをいじります


・コントラストが出せるようなシチュエーション

・ライティングをリアルにしようと傾ける

・空気感を出すためにフォグとか出す


みたいなことをすると盛り上がる。


Tips

timelineに複数の視点を置いて、エディタ上で動かすことで他視点をテストしやすくなる。

↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑


このTipsクッソ便利だわ、、、それ用のツール作ろうかな。視点一個置くと勝手にTimeline生成してくれるやつ。


wrote 2018/05/08 10:17:26

テストツールでLoadScene -> UnloadAsync した時だけ発生するバグ


概要

UnityTestTool、便利なんだけど、一点面白い挙動を見つけた。

特定条件下でUnloadSceneAsyncが失敗する。


通常のPlayでは発生せず、UnityTestの中でだけ失敗する。安心(?)



再現リポジトリ

https://github.com/sassembla/TestWithLoadSyncThenUnloadAsync/tree/master



対象

Unity2017.3.1p4、Unity2017.4.0f1

ほかにもあるかもしれないが検証は各位の宿題とする。



条件

UnityTestの中で、LoadSceneを使う + そのシーンをUnloadAsyncしようとすると、UnloadAsyncがnullを返してきて詰む。


次のようなLoadSceneAsyncを使ったコードだと平気で、

[UnityTest]

public IEnumerator Async()

{

    var cor = UnityEngine.SceneManagement.SceneManager.LoadSceneAsync("Assets/AutoyaTests/RuntimeData/bundledScene.unity", UnityEngine.SceneManagement.LoadSceneMode.Additive);

    while (!cor.isDone)

    {

        yield return null;

    }


    var unloadCor = UnityEngine.SceneManagement.SceneManager.UnloadSceneAsync("Assets/AutoyaTests/RuntimeData/bundledScene.unity");

    while (!unloadCor.isDone)

    {

        yield return null;

    }

}



次のような、LoadSceneを使ったコードだと、unloadCorがnullで吹っ飛んでくる。

[UnityTest]

public IEnumerator Sync()

{

    UnityEngine.SceneManagement.SceneManager.LoadScene("Assets/AutoyaTests/RuntimeData/bundledScene.unity", UnityEngine.SceneManagement.LoadSceneMode.Additive);


    var unloadCor = UnityEngine.SceneManagement.SceneManager.UnloadSceneAsync("Assets/AutoyaTests/RuntimeData/bundledScene.unity");

    while (!unloadCor.isDone)

    {

        yield return null;

    }

}


再現リポジトリのUnityTestを実行すると、Asyncは通過して、Syncは失敗する。


こちらからは以上です。レポートしとこ。



wrote 2018/04/25 14:58:34

小田原・リム 温泉ライジングのしおり


概要

4/29(日曜)

新宿集合、小田急ロマンスカーで小田原へ、そして禅(回る寿司屋)、小田原コロナワールドへタクシー、パシフィック・リム アップライジング4DXを見る or 温泉(順不同)


電車

はこね55号

9:25 新宿発、10:40 小田原着



集合

9:10分には小田急線の乗り場に到着してるのが理想。

切符はその場で買うのだ!多分大丈夫。

wrote 2018/04/23 12:04:25

Unity IAPの更新方法


概要

こうしないとインポート時に100%Unity Editorが落ちる、という確証が取れたのでまとめる。

ちなみにこれを実践しても何度か落ちる可能性がある。IAPのアプデしたいだけなんだが(報告中)


1.IAPを使っているコードをコンパイル対象から外す

2.IAPの入っているPlugins/UnityPurchasing フォルダを消す

3.一旦Unity終了、プロジェクト直下のLibraryフォルダを消す

4.Unity起動、ServicesからIAPをImport

5.ServicesからIAPをReimport

6.Plugins/UnityPurchasing フォルダ内にunitypackageができるので、それを使う


こんだけやるとIAPを最新にできる。なぜだ。



1.IAPを使っているコードをコンパイル対象から外す

なんかコンパイラディレクティブとか使って、特定状況下ではPurchasingとそれに依存するコードを丸ごとコンパイル対象から外す、みたいなことをするといいと思う。

Purchasing系に依存してるコードがある状態でIAP更新すると100%エディタが落ちる。



2.IAPの入っているPlugins/UnityPurchasing フォルダを消す

フォルダを消しても依存がないのでコンパイルエラーが出ないはず。



3.一旦Unity終了、プロジェクト直下のLibraryフォルダを消す

Libraryフォルダを消す。これをやらないとやはり落ちる。



4.Unity起動、ServicesからIAPをImport

ログイン済み + IAPをEnableにする、という操作が終わっていればImportやReimportボタンが出る。

押すと、、中確率くらいでUnityEditorが落ちる。


2でフォルダを消しているので、Importになっているはず。



5.ServicesからIAPをReimport

Importが終わったら、再度Services > IAP でReimportを押す

押すと、、中確率くらいでUnityEditorが落ちる。


6.Plugins/UnityPurchasing フォルダ内にunitypackageができるので、それを使う

ここまででPlugins/UnityPurchasingフォルダ下にunitypackageが2つできているはずで、

できていない場合Reimportが足りない。


何を言っているのかわからねーと思うが本当にそう。

Reimportしまくると出てくる。自分は最大3回くらいReimportした。


スクリーンショット 2018-04-19 14.13.23.png

UnityIAP.unitypackage を使うとこで、正しくいろいろ入った状態のIAPが使えるようになる。


最後に1で立てたdefineとかを消して、元来の機構のコンパイルを通して完了となる。



やらないとどうなるの?

using Unity.Purchasing の内容にストア情報が含まれなかったり StandardPurchasingModule.Instance() のコンパイルが通らなかったりする。

原因は単純で、dllが異なるっぽい。


unitypackageに含まれてるdllが正しい。それ以外はダメ。



楽な方法はないの

UnityIAPを空のプロジェクトに入れて、そこで出てきたunitypackageを対象のプロジェクトに対して使う。

なんでやねんという感じがするが、本当にこれ。



もしかしてAssetStoreの方のやつをそのまま使うと良かったりする?と何回か試したことがあるが、

うまくいったりいかなかったりで再現性がないんで再現性があるこの手法を紹介する。



wrote 2018/04/19 11:08:42

逆引きk8s


概要

覚えるの面倒くさいのでメモ。



podの概念

pod = クジラの群れ、というトリビアレベルの何かがあって、コンテナの群れだよ、という話らしい。出典:入門Kubernetes



podのstdoutをtailする

kubectl logs -f <pod>



podとローカルの間でのファイルのやりとり

kubectl cp <pod>:somewhere_path /local_path

kubectl cp /local_path <pod>:somewhere_path 



podへの侵入

kubectl exec -it <pod> -- bash



imageだけ変更して読み出したい場合

kubectl replace -f <yaml or json>



wrote 2018/04/12 12:24:37

Unity 2017.3以降のUnityWebRequestの話


概要

2017.2 ~ 3の間で仕様変更があって、ただそのことについてしっかり書いてるところを見たことがなかったのでまとめる。

AutoyaのテストでHTTP系のやつがあってそれで気づいた。



発端

Unity2017.3から、UnityWebRequestがデフォルト設定ではcontent-lengthをつけなくなった。

これはバグじゃね?って話でissueが上がったりしていた。


WWW REQUEST DOESN'T SEND CONTENT-LENGTH HEADER

https://issuetracker.unity3d.com/issues/www-request-fails-to-get-content-length-header


具体例

デフォルトのUnityWebRequestのヘッダが以下のように変わる。

2017.2系まで

2.png



2017.3系以降

3.png

このとき、両versionとも、UnityWebRequestのchunkedTransferは、デフォルトのtrueのまま。



お分かりいただけただろうか?



2017.2系だと、chunkedTransfer = trueなのにTransfer-Encodingが全く入っておらず

かつContent-Lengthが入っている


2017.3系だと、chunkedTransfer = trueなのでTransfer-Encoding: chunked が入っていて

Content-Lengthが入っていない



Content-Lengthとchunkedの関係は、RFC2616にいろいろ書いてある。

https://tools.ietf.org/html/rfc2616


簡単に書くと、2017.2まではchunkedTransfer = trueなのにchunkedになってないリクエストを送っていた。

chunkedありなしとサーバ側の挙動の関係でいえば、


Messages MUST NOT include both a Content-Length header field and a

  non-identity transfer-coding. If the message does include a non-

  identity transfer-coding, the Content-Length MUST be ignored.

みたいな記述があり、両方入っている場合はContent-Lengthが無視される。



ということで、バグっていたのは2017.2までで、Unity側はどっかでこのことに気づいて手を入れ(どこかのパッチリリースだった気がする、忘れた)、

デフォルトの状態のUnityWebRequestのヘッダパラメータからはContent-Lengthが消えた。


このため、例えば自分がテストに使っている、httpbin.org(https://httpbin.org)とかが、chunkedに対応してなくてcontent-lengthないよ~ってエラーを返してきたりしていた。

対処

えーーっと、2017.3以降は、chunkedを使いたい場合はそのまま、使いたくない場合はchunkedTransfer = falseとする必要がある。

2017.2以前で、最新のパッチリリースはともかく、chunkedを使いたい場合は、、えーーーーっと、、まあ、、誰か試して。自分はもう2017.3以降に対応することにしたんで、、


教訓

パラメータが一切変わらなくても要素が変わることがあり、それに対してテストで気づけたので、まあ、はい。

テストは自分を助けてくれる。



wrote 2018/03/24 18:26:28

GKEで遊ぶ時の手順


概要

メモまでに、GKEで遊ぶ/遊んだ時のいろいろを書いておく。



SDK入れる

gcloud何ちゃら入れる



クラスタ用意する

https://console.cloud.google.com/kubernetes/

から頑張る


ContainerRegistryにアップするDocker imageを作る

ふつーにbuildで作成する。



作成したimageをContainerRegistryにアップする

タグつけてgcloudコマンドでアップ。タグつけるときにtagをつけなければ自動的にlatestがつく。

docker tag image_name asia.gcr.io/project_name/image_name:tag

gcloud docker -- push asia.gcr.io/project_name/image_name



ContainerRegistryにアップしたコンテナをGKEで使う

さきほどpushしたものがgcloudから検知できるかチェック

gcloud container images list-tags asia.gcr.io/project_name/image_name

で、なんかヒットするはず。

Deploymentを作成してGKEへとデプロイ

手元のマシンのkubectlの設定を変え、接続対象をGKEの特定のクラスタへと変更する。

まずはkubectlの現在のコンテキスト(接続先)を確認。

kubectl config current-context


で、接続先がGKEの意図したクラスタでない場合、gcloudコマンドを使ってそのパラメータを変更する。

gcloud container clusters get-credentials your_cluster_name --zone your_zone


この状態でもう一度current-contextをみると、変わっているはず。

gke_your_project_name_asia-east1-a_your_cluster_name


つまりクラスタ毎にデプロイしたい場合はこれらのコマンドを使っていちいちクラスタ切り替えないと行けないわけだね。

手元からやるもんじゃねーな。

role.json

{

   "apiVersion": "extensions/v1beta1",

   "kind": "Deployment",

   "metadata": {

      "name": "role-deployment",

      "labels": {

         "app": "role"

      }

   },

   "spec": {

      "replicas": 1,

      "selector": {

         "matchLabels": {

            "app": "role"

         }

      },

      "template": {

         "metadata": {

            "labels": {

               "app": "role"

            }

         },

         "spec": {

            "containers": [

               {

                  "name": "role",

                  "image": "asia.gcr.io/dev-milive/dev-role",

                  "ports": [

                     {

                        "containerPort": your_port2

                     },

                     {

                        "containerPort": your_port

                     }

                  ]

               }

            ]

         }

      }

   }

}


で、kubectl apply コマンドでデプロイできる。

kubectl apply -f role.json


この時点でGKEのページからデプロイ済みの確認が取れた。ノードの詳細画面の一番下にデプロイされてるのを確認。


role.jsonには次のようなパラメータをセットしてたんだけど、

{

   "apiVersion": "extensions/v1beta1",

   "kind": "Deployment",


これ、なんでextensions/v1beta1 とかになるんだろう。minikubeでやってたみたいにapps/v1ではいけないんだろうか?

-> ここの設定に則ってるっぽい。 k8s公式。

https://kubernetes.io/docs/reference/generated/federation/extensions/v1beta1/definitions/


デプロイ済みの要素にアクセスする

次に、外部からアクセスできるようにserviceを設定する。このへんもjson書いてやる。

kubectl create -f svc_role.json 


複数のポートの指定もできてると思うんだけど、アクセスができない。なんでだろ。

https以外でのアクセスができない + コンテナがそれに対応してない的な?

-> 違った。


kubectl expose deployment -l app=role -p your_port --type "LoadBalancer"

とかダイレクトにやったら接続できた。やったぜ!

ということはファイルで書いたServiceの記述がまちがっている。


x role    LoadBalancer   10.35.248.38   104.199.151.125   your_port2:30247/TCP,your_port:30368/TCP   12h

o role-deployment   LoadBalancer   10.35.250.167   35.229.178.174   your_port:31518/TCP   2m


なるほど、exposeしてる対象が異なるのか。さらになんか違いそう。

kubectl expose deployment role-deployment --port=your_port,your_port2 --type="LoadBalancer"

とかだと複数portいけた。やったぜ。で、

じゃあこれはどんなデータになってるんだろう、、、jsonにできないとつらいぞ、、

-> get svc 名前 -o yamlで取り出して云々して比較した。jsonでも取り出せる? -> 出せた。


kubectl get svc role-deployment -o json



ということで、一度コマンドラインで作ってからうまくいったらjsonにして云々みたいなテクを覚えた。

いい感じに動くようになった~~わーい。

最終的なサービスを作成するためのjsonはこれ


svc_role.json

{

    "apiVersion": "v1",

    "kind": "Service",

    "metadata": {

        "labels": {

            "app": "role"

        },

        "name": "role-deployment"

    },

    "spec": {

        "ports": [

            {

                "name": "p1",

                "port": your_port

            },

            {

                "name": "p2",

                "port": your_port2

            }

        ],

        "selector": {

            "app": "role"

        },

        "type": "LoadBalancer"

    }

}


教訓:

・deploymentにつける名前とserviceにつける名前で一致してないと行けない部分がある。

・selectorについてもっと学ぶ必要がある。どんな指向性してるんだかをもっと把握しないとな=~。



ContainerBuilderを使ってコードからDockerImageをビルド(おまけ)

ビルドリクエストを出してDocker imageを生成する。

githubとかから引っ張り出して実行できる模様。

このへんのパイプラインを構築しないとな。


少なくともcontainerRegistryへのアップとかは手元からやるルートと自動化ルートの両方が欲しい。



wrote 2018/03/23 16:00:29

k8sの基本を学ぶ


概要

必要が出たので学ぶ。



k8sについて

適当に平易な言葉を使って表現すると、

・クラスタリングしたコンテナのコントロールを行うコマンドラインツール

kubectl コマンドにいろいろなオプションをつけるとコンテナ群をいい感じに管理してくれる。



いろいろな用語


MasterとNode

Masterが総合的なサービスのコントローラ、Nodeがコンテナの実行部分。



Resource

k8sにはいろいろな要素グループがあり、総称はResource


Resourceという要素の中に、Pod、Node、Masterなどがある。

全ての要素にlabelをつけることができる。

namespaceという単位で括ることができる。何も指定しない場合default。


Pod

1つ以上のコンテナが入ったResource。

k8sではこの単位でアプリケーションを運用する。

この単位でNodeにデプロイされる。


Service

Resourceへのインターフェースを提供するResource

labelでPodを判別し、インターフェースを提供する。



ReplicaSet

Podの調整を行う関数みたいなResource。

labelに則ってPodを検索し、指定した数値と見つかったPodの多寡で調整を行う。


Deployment

アプリケーションのアップデートやロールバックを宣言的に行うためのResource。



とりあえず基礎はこんなところか。



minukubeを使ってうごかしてみる

依存

mac用だとhyperkitとかに依存してる。で、これはdocker入れたら入ってるっぽいんだよな。

-> dockerが持ってるHyperkitとの橋渡しのドライバがあるみたいだ。下記で入れる。

curl -LO https://storage.googleapis.com/minikube/releases/latest/docker-machine-driver-hyperkit \

&& chmod +x docker-machine-driver-hyperkit \

&& sudo mv docker-machine-driver-hyperkit /usr/local/bin/ \

&& sudo chown root:wheel /usr/local/bin/docker-machine-driver-hyperkit \

&& sudo chmod u+s /usr/local/bin/docker-machine-driver-hyperkit



minikubeのインストール

curl -Lo minikube https://storage.googleapis.com/minikube/releases/v0.25.0/minikube-darwin-amd64

これ以外のバージョンだと動作しなかった。こえーー。


具体的にいうと、kubectl 1.9.0とminikube 0.25.0の組み合わせ以外で動かなかった。



起動

minikube start --vm-driver=hyperkit


パラメータはconfigでセットしておくことができる。

minikube config set vm-driver hyperkit



状態

minikube status

minikube: Running

cluster: Running

kubectl: Correctly Configured: pointing to minikube-vm at 192.168.64.6



imageのデプロイと実行

kubectl run hello-minikube --image=k8s.gcr.io/echoserver:1.4 --port=8080

imageとportを指定して投入する。

この時点でport 8080にアクセスしても何も起こらない。


投入されたコンテナはpodに入る = podが生成される。

kubectl get pod

NAME                            READY     STATUS    RESTARTS   AGE

hello-minikube-c6c6764d-f8nhg   1/1       Running   0          5m

ラベル付きのものを取得したい場合、-l k=v とかやると抽出できる。



実行するとdeploymentが生成されているので、検知できるようになる。

kubectl get deployment

NAME             DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE

hello-minikube   1         1         1            1           9m



deploymentについての記述を見てみる。

kubectl describe deployment hello-minikube


これで元になっているimageとか空いてるポートとかが確認できる。



deploymentへと接続するhello-minikubeというサービスを生成

kubectl expose deployment hello-minikube --type=NodePort



hello-minikube サービスのurlを取得(urlオプション無しだと自動的にブラウザで開く)

minikube service hello-minikube --url



削除、deploymentとserviceを消す。

kubectl delete deployment hello-minikube

kubectl delete service hello-minikube


概念的には、


1.runでpodがデプロイされ、指定した名前のdeploymentリソースが生成される。

2.生成されたdeploymentに対して、expose 名前指定 + 接続オプションで、外部からアクセス可能なipとポートが生成される。

という感じで、デプロイ -> サービス生成 という手順を踏むと公開される。


接続オプションにはNodePortとLoadBalancer、Ingress がある。

minikubeで使えるのはNodePortのみ。実際にはLBかIngressを使うっぽい。



ファイルをもとにdeployを行う

yamlの視認性はヤバいのでjsonで。


dep.json

{

   "apiVersion": "apps/v1",

   "kind": "Deployment",

   "metadata": {// デプロイ自体の設定

      "name": "nginx-hostname-deployment",

      "labels": {

         "app": "nginx-hostname"

      }

   },

   "spec": {// replicaとかtemplate、selectorが所属する属性。

      "replicas": 1,

      "selector": {

         "matchLabels": {

            "app": "nginx-hostname"

         }

      },

      "template": {

         "metadata": {

            "labels": {

               "app": "nginx-hostname"

            }

         },

         "spec": {

            "containers": [

               {

                  "name": "nginx-hostname",// 名前

                  "image": "stenote/nginx-hostname",// 元にするイメージ

                  "ports": [// exposeするポート

                     {

                        "containerPort": 80

                     }

                  ]

               }

            ]

         }

      }

   }

}


これを実行する。

kubectl apply -f dep.json


すると、nginx-hostname-deploymentというdeploymentが作成される。


podとreplicaSetについて指定してあり、それらが生成されている。

その状態はkubectl get pod -l app=nginx-hostname とかで取得できる。

deplpyment name指定でserviceを作成、公開状態にする。

kubectl expose deployment nginx-hostname-deployment ---type=NodePort


で、公開済みのserviceの情報を見るには下記が使える。

kubectl get service nginx-hostname-deployment

kubectl describe service nginx-hostname-deployment


ここから、このセットをスケールアウトさせてみる。

kubectl scale --replicas=5 deployment nginx-hostname-deployment

これで5つまでスケールする。(ここではオフラインで実行したんで失敗してる。)

kubectl get pod -l app=nginx-hostname

NAME                                        READY     STATUS             RESTARTS   AGE

nginx-hostname-deployment-8b65c84d7-6qzjj   1/1       Running            0          1h

nginx-hostname-deployment-8b65c84d7-77mv7   0/1       ErrImagePull       0          54m

nginx-hostname-deployment-8b65c84d7-7996w   0/1       ImagePullBackOff   0          54m

nginx-hostname-deployment-8b65c84d7-smc4w   0/1       ErrImagePull       0          54m

nginx-hostname-deployment-8b65c84d7-vlhkb   0/1       ErrImagePull       0          54m


scaleやりなおしてもimagePullBackOffから帰って来なかったやつが一機あったのが気になる、、、、



ということで、scaleコマンドでスケーリングできる。もちろんこれは減らす方向にも向かえる。


整理すると、

1.deploymentの設定ファイル書く

2.実行するとデプロイが行われる。書かれているimageが使われる

3.sca;eコマンドでdeployment/設定名 でスケーリングできる


となる感じで、これは便利。



APIまとめ

デプロイする

kubectl apply -f dep.json



デプロイ済みのものを公開する

kubectl expose deployment デプロイ名 ---type=NodePort

-> 指定したdeploymentに対して同じ名前のserviceが生成される。

-> typeはいろいろある(minikubeではNodePortしか使えない)



公開したデプロイのurlを得る(ここだけminikube)

minikube service hello-minikube --url

serviceとdeploymentは独立しているため、deploymentを消してもserviceは影響を受けない(ルーティング的には影響を受けそうだが)



スケールさせる

kubectl scale --replicas=5 deployment デプロイ名



非公開にする

kubectl delete service サービス名



停止させる

kubectl delete deployment デプロイ名





今のところの所感

apply、run、scale、delete、get、set、expose、describeとかは動詞的、

pod、service(svc)、deploymentはリソースの指定のkind扱い、resourceのフィルタに使われている感じ。

さらに-lオプションでのラベルでのフィルタリングがある。



wrote 2018/03/22 20:25:55

Unityでprotobufを使う


概要

2018年ともなると選択肢増えていた。



避けたいこと

attrでの生成

なぜ変更可能性をわざわざ下げねばならないのか。IDLあるんだからそっちを主にしようよ。



やりたいこと

.proto ファイルからのコード生成


ドンピシャなのがこれ。

https://github.com/5argon/protobuf-unity



やらないといけないこと

iOS向けに、事前に生成されたcsコードをdllにしておく必要がある。



protobufのインストール

macだとhomebrewが楽。

brew install protobuf


で、入れ終わったら

/usr/local/bin/protoc

で出て来るパスをUnity > Preferences > Protobuf に指定する。


この時入っているverは3.5.1。



Unity側のprotobuf.dllの更新

含まれているdllが古いため、protobuf本家のリポジトリ https://github.com/google/protobuf からcsharp用のdllを生成する。

protobuf 3.5.1のdotnet fw 4.5あたりでのdllが落ちてると嬉しいんだけど。



と言うわけでなんとかなるようにしたのがこちらのリポジトリ(fork)

https://github.com/sassembla/protobuf-unity


wrote 2018/03/03 5:02:33

Streaming Conf行ってきた


RTMP1.0 by go


RTMP

tcpベース、いろいろ。

Wowzaサーバに対して現場から生放送したデータをアップ、みたいなところに使っている。

TCPで好きにぶん投げるのだとまずいので、タイムスタンプをいっぱい入れている。


ffmpegと通信する?

ffmpeg大活躍だな。


チャンクストリーム

データはチャンク単位に分割される。

-> でかい物を送って詰まるのを防ぐため。


種類いっぱいある。

AMF アクションメッセージフォーマット みたいな圧縮データを送るのもある。



nginx-rtmp-mod と wowzaの間の会話をみたらこんな感じだった

~ みたいなのがgithubにあるそう。みよう。



Showroomの人の話

ShowroomではCDNを使った配信をしていない。

ほー?



通知が出るので配信開始時にグッと負荷がかかる

あらかじめ予測してマニュアルでスケールアウトさせておく。

誕生日だからくるぞ

未公開情報の開示だからくるぞ

みたいな読みを効かせる

結局人力かよみたいな。


告知SNSでのいいね数とか。



WebRTCとHLSの話



HLSの配信を高速化

300msくらいまでいけたらしい。すごいね。


youtubeはCMAFを使っていて速い(2秒


提案手法では350ms


プレイリストをからの状態からアップしちゃって書き込み続ける


HLS処理を改善した件

モイ株式会社、ツイキャスの中の人。


生放送に特化。Cで全部書く人。

nodeで

rtmp -> hls

flv -> h254 mpegtsとかに。



調停遅延HLS

みんな作ってるんだなあ。



同じくツイキャスの中の人

同時1万人 AWS wowzaとかはなし。お金がなくなっちゃう。

ほーー



1Mbpsはモバイルにはまだ速い

100kbpsくらいで、、


softbankの回線だけ特殊なんで、何か用意しないといけない

-> もうちょい詳しく聞いてみたかった。


キーフレームを使いまわしている

ラジオ放送とかで静止画を流す場合はもうエンコーダー止まってる



びんづめさん


配信システムを作ろうとした時の話

コーデック

h264とか

映像 + 音声


コンテナ

FLV、MPEG tsとか


コンテナに含まれるのは

コーデック情報

パラメータ


ストリームデータ

タイムスタンプ

エンコード済みデータ

+ アルファ キーフレームかどうかなど。



PTSとDTS

Presentation ts

いつ表示されるか


Decode ts

データのデコード順に関してフラれた時刻

映像のBフレームなど、前後の情報が必要。



メテオさん

bitrateを改善して配信量を減らした話


H264 + Opusで配信

6-9秒の遅延

CBRからVBRに変換。


FFMpegのh264エンコーディングガイドを熟読しよう




wrote 2018/02/26 19:38:42

Autoyaチェックリスト


概要

OverridePointsのこの項目をいい感じに改変できると良いと思う。特にセキュリティ的な部分で。



authentication handlers.


1.初回通信に使うバイナリキー、良い感じの形式のものを良い感じの暗号化して送るべき。

private IEnumerator OnBootAuthRequest(Action<Dictionary<string, string>, string> setHeaderAndDataToRequest)

{

    // set boot body data for Http.Post to server.(if empty, this framework use Http.Get for sending data to server.)

    var data = "some boot data";


    // set boot authentication header.

    var bootKey = AuthSettings.AUTH_BOOT;

    var base64Str = Base64.FromBytes(bootKey);


    var bootRequestHeader = new Dictionary<string, string> {

        {"Authorization", base64Str}

    };


    setHeaderAndDataToRequest(bootRequestHeader, data);

    yield break;

}



2.初回起動時のサーバからの通信に対して、クライアント側でチェックし、validかどうか判断すべき。validだったら、暗号化してtokenデータを保存する。

この例ではtokenしか保存していないが、refreshTokenも暗号化して保存する必要がある。

private IEnumerator OnBootAuthResponse(Dictionary<string, string> responseHeader, string data, Action<int, string> bootAuthFailed)

{

    var isValidResponse = true;

    if (isValidResponse)

    {

        Autoya.Persist_Update(AuthSettings.AUTH_STORED_FRAMEWORK_DOMAIN, AuthSettings.AUTH_STORED_TOKEN_FILENAME, data);

    }

    else

    {

        bootAuthFailed(-1, "failed to boot validation.");

    }

    yield break;

}



3.リフレッシュトークンの送信。保存してあるrefreshTokenを復号する必要がある。このコードではまんま保存しておいたtokenを送っているため、保存するところから変えないと行けない。

private IEnumerator OnTokenRefreshRequest(Action<Dictionary<string, string>, string> setHeaderToRequest)


    // set refresh body data for Http.Post to server.(if empty, this framework use Http.Get for sending data to server.)

    var data = "some refresh data";


    // return refresh token for re-authenticate.

    var refreshToken = Autoya.Persist_Load(AuthSettings.AUTH_STORED_FRAMEWORK_DOMAIN, AuthSettings.AUTH_STORED_TOKEN_FILENAME);


    var base64Str = Base64.FromString(refreshToken);


    var refreshRequestHeader = new Dictionary<string, string> {

        {"Authorization", base64Str}

    };


    setHeaderToRequest(refreshRequestHeader, data);

    yield break;

}



4.リフレッシュトークンの受信。validationしてOKだったら、新たに得たtokenとrefreshTokenを暗号化して保存。

private IEnumerator OnTokenRefreshResponse(Dictionary<string, string> responseHeader, string data, Action<int, string> refreshFailed)

{

    var isValidResponse = true;

    if (isValidResponse)

    {

        Autoya.Persist_Update(AuthSettings.AUTH_STORED_FRAMEWORK_DOMAIN, AuthSettings.AUTH_STORED_TOKEN_FILENAME, data);

    }

    else

    {

        // failsafe here.



        // set result as failure.

        refreshFailed(-1, "failed to refresh token.");

    }


    yield break;

}



authorized http request & response handlers.


5.JWTなどのdigest生成を行うのはここ。

private Dictionary<string, string> OnHttpRequest(string method, string url, Dictionary<string, string> requestHeader, string data)

{

    var accessToken = Autoya.Persist_Load(AuthSettings.AUTH_STORED_FRAMEWORK_DOMAIN, AuthSettings.AUTH_STORED_TOKEN_FILENAME);

    requestHeader["Authorization"] = Base64.FromString(accessToken);


    return requestHeader;

}



6.レスポンスに対してのチェックを行うのはここ。(string)

private bool OnValidateHttpResponse(string method, string url, Dictionary<string, string> responseHeader, string data, out string reason)

{

    // let's validate http response if need.

    var isValid = true;

    if (isValid)

    {

        reason = string.Empty;

        return true;

    }

    else

    {

        reason = "run over by a bicycle.";

        return false;

    }

}



7.レスポンスに対してのチェックを行うのはここ。(byte[])

private bool OnValidateHttpResponse(string method, string url, Dictionary<string, string> responseHeader, byte[] data, out string reason)

{

    // let's validate http response if need.

    var isValid = true;

    if (isValid)

    {

        reason = string.Empty;

        return true;

    }

    else

    {

        reason = "run over by a bicycle.";

        return false;

    }

}



purchase feature handlers.


8.サーバ側が最新状態を持っているので、必要があれば課金関連のパラメータを更新する。

private void onPaidPurchaseDoneInBackground(string backgroundPurchasedProductId)

{

    // server deployed some products for this player. update player's parameter if need.

}



AssetBundles handlers.


9.リストを保存する際に暗号化すると良い。

private AssetBundleList[] LoadAssetBundleListsFromStorage()

{

    // load stored assetBundleList then return it.

    var filePaths = Autoya.Persist_FileNamesInDomain(AssetBundlesSettings.ASSETBUNDLES_LIST_STORED_DOMAIN);

    return filePaths.Select(

        path => JsonUtility.FromJson<AssetBundleList>(

            Autoya.Persist_Load(

                AssetBundlesSettings.ASSETBUNDLES_LIST_STORED_DOMAIN, Path.GetFileName(path)

            )

        )

    ).ToArray();

}



10.リストを更新する際、暗号化すると良い。

private bool StoreAssetBundleListToStorage(AssetBundleList list)

{

    var listStr = JsonUtility.ToJson(list);

    var result = _autoyaFilePersistence.Update(AssetBundlesSettings.ASSETBUNDLES_LIST_STORED_DOMAIN, list.identity, listStr);

    return result;

}



11.AssetBundleListのGet時に発効。CDNに何かしらアクセス保護を仕込んである場合、ここでパラメータを入れる。

private Dictionary<string, string> OnAssetBundleListGetRequest(string url, Dictionary<string, string> requestHeader)

{

    return requestHeader;

}



12.PreloadListのGet時に発効。CDNに何かしらアクセス保護を仕込んである場合、ここでパラメータを入れる。

private Dictionary<string, string> OnAssetBundlePreloadListGetRequest(string url, Dictionary<string, string> requestHeader)

{

    return requestHeader;

}



13.AssetBundleのGet時に発効。CDNに何かしらアクセス保護を仕込んである場合、ここでパラメータを入れる。

private Dictionary<string, string> OnAssetBundleGetRequest(string url, Dictionary<string, string> requestHeader)

{

    return requestHeader;

}



ApplicationManifest handlers.


14.RuntimeManifestの上書き。暗号化すると良い。

private bool OnOverwriteRuntimeManifest(string data)

{

    return _autoyaFilePersistence.Update(AppSettings.APP_STORED_RUNTIME_MANIFEST_DOMAIN, AppSettings.APP_STORED_RUNTIME_MANIFEST_FILENAME, data);

}



15.RuntimeManifestの取り出し。復号化すると良い。

private string OnLoadRuntimeManifest()

{

    return _autoyaFilePersistence.Load(AppSettings.APP_STORED_RUNTIME_MANIFEST_DOMAIN, AppSettings.APP_STORED_RUNTIME_MANIFEST_FILENAME);

}


wrote 2018/02/25 18:28:00

docusaurusで遊ぶ


概要

Autoyaのドキュメントの既存資産部分をプレゼンテーションスタイルからちゃんとしたドキュメントに移動する、というのをずっとやっていた。

んで目処が立ったんで最新化も行うなど。去年末くらいから開始して結構かかったな、、、



使っているもの

docusaurus

https://docusaurus.io


目次があるドキュメントツールが欲しかったので選んだ。



インストール

いろんなところに書いてあるんではい。公式。

https://docusaurus.io/docs/en/installation.html


構造的な概要

つぎのようなファイルを基礎に成立している。フォルダ名は鬱陶しいのでverifyを終えた時のものに合わせてある。




markdownで書かれたexampleなドキュメンテーション記事置き場






サイト構築に際して

簡単なページを作ってみる。

条件として、


・ファイル名と内部で記述するidが一致すること

・必ずヘッダーパラメータを入れること


などがある。

ヘッダーパラメータは次のようなもので、

---// このへんから

id: install0

title: Install Autoya to your project

sidebar_label: Installation

---// このへんまで


リリースにUnitypackageファイルがあるんで、その辺を選んで使うと楽。


idはファイル名に一致したもの、

titleはmdとは無関係に一番上に出る文字列、

sidebar_labelは、[この名前のsidebarの下にぶら下がる]という宣言になっている。

sidebar_labelがないと、そのページを表示する際にはサイドバーがないページが出てくる。



サイドバーをいじる

サイドバーはjsonになっている。

website/sidebars.json をいじることで編集できる。


こんな感じ。

{

  "docs": {

  "Getting started":["install0"],

"API":["api0"]

  },

  "docs-other": {

    "First Category": ["doc4", "doc5"]

  }

}


各ページのidを記述することで、簡単に目次が作れて便利。

docs-otherは表示されないっぽい。


サイドバーからコンテンツへとジャンプ、

コンテンツ間はコンテンツ間でリンク、

コンテンツにsidebarの表記がなければページ上もサイドバーが出ない、

みたいな挙動になっている。


サイドバー、概念的には

・一番大雑把な特性で所属をわける

Document、API、他、みたいな。


・Docはこのサイドバー、APIはこのサイドバー、みたいな概念ではない

ないっぽい。複数サイドバーみたいなissueが上がってそうな気はするが。


・サイト内で複数種類のサイドバーをせっていすることが可能。

こんな感じにした。


sidebars.json

{

  "docs": {

  "Installation": ["install0"],

  "Overview": ["overview0", "overridepoints0"],

  "Documents": [

  "auth0",

  "manifest0",

  "persistence0",

  "assetbundle0",

  "connection0",

  "maintenance0",

  "purchase0",

  "notification0",

  "information0",

  "settings0"

  ],

  "Resource Management":[

  "resource_generate0",

  "resource_deploy0"

  ],

  "App Management": [

  "update_app_version0",

  "update_resource_version0",

  "turn_on_maintenance0"

  ]

  },

  "api":{

  "APIs": [

  "api_auth0",

  "api_manifest0",

  "api_persistence0",

  "api_assetbundle0",

  "api_http0", "api_udp0",

  "api_maintenance0",

  "api_purchase0",

  "api_information0"

  ]

  }

}


これで、docsとapiというサイドバーが作れる。

この名称はサイト上には一切現れないため、単に区別のためだけにある感じ。



ビルド

websiteフォルダー下で

yarn run build

とかやると、ビルドされる。

website/buildとかフォルダが生成される。

github pages向けだと、次のコマンドがあり、

yarn docusaurus-publish


できた中身をgithub pagesに関連づければよさげ。



Tips

blogは、yyyy-mm-dd-ファイル名.md でないとダメだとか。


Question

ライブリロードどうなってんの

https://github.com/facebook/Docusaurus/issues/234

-> 中にexpressが入ってるんで頑張ればできそうなんだけど、今のとこ無理。

mdで書くドキュメント類は単に更新すればhtmlに変換されて良いのだけれど、sidebarとかfooterの内容はコンパイルが必要なのか更新されない。


自分はyarn run startをした状態で別ターミナルで yarn run build とかでしのいでいる。

このへんはwatchで自動化すると良さそう。


docsの下にフォルダ掘りたいんだけどできないものか

https://github.com/facebook/Docusaurus/issues/323

-> 書き換えられるけどできない。flattenみたいなのを使う必要がある。


en から他の言語への切り替え

デフォルトを日本語で書いている(enなんだけどね)

https://docusaurus.io/docs/en/translation.html

-> まだ見てない。


検索窓

なんか有効にできるっぽい。

https://docusaurus.io/docs/en/search.html

-> まだ見てない。


やったことあるひといた。

http://efcl.info/2017/12/26/docusaurus-almin/



wrote 2018/02/18 0:34:56

UUebView チートシート


概要

・なんぞや

・サンプルについて

・簡単な使い方

・独自タグの作り方

・UUebViewからTMProを使うには

などを書く。



なんぞや

これ。

UUebView

https://github.com/sassembla/UUebView-freeversion


htmlコンテンツをuGUI上で描画できるWebView。

独自タグをuGUIで作ることができ、スクリプトやアニメーションのアタッチなども可。



が、断っておくと、そのへんのWebサイトで表示されているようなコンテンツはほぼ100%表示されない。なぜならこいつは、

Unity上で作ったいろいろなレイアウト情報やらスタイル情報やらオリジナルタグを、HTMLで記述して表示する、というものだから。

何がいいたいかというと、CSSとかJSをガン無視したパーサやレイアウターが書かれているうえ、

受け付けるHTMLファイル上のDOCTYPE指定はuuebviewという、完全独自のものなので。


サンプルについて

masterブランチは通常のuGUIを使ったビューの表示、

TMProEnabledブランチはTextMesh Proのテキストを使ったビューの表示を行うサンプルが入っている。


TMPro使ってみてほしいからTMProEnabledブランチで試すのがオススメ。



uGUI Text版


masterブランチをダウンロード -> Assets/Sample/SampleSceneを開く -> Play

これで、uGUI Textを使ったコンテンツの表示が行われる。表示されるコンテンツは Assets/Sample/Resources/items.html 。


こんなのが出る。

スクリーンショット 2018-02-16 15.52.01.png


uGUIでこんな感じのレイアウトベースみたいなものを作り、

スクリーンショット 2018-02-16 21.55.59.png

これらをHTMLタグに変換し、htmlから参照、レイアウト、変形させて使っている。

背景はimageの9パッチで伸縮している。これももちろんHTMLタグ。



TMPro Text版


TMProEnabledブランチをダウンロード -> Assets/Sample/SampleScene2_TMProPluginを開く -> 

TextMesh ProをAssetStoreから落としてくる -> Play


これで、TextMesh Pro Textを使ったコンテンツの表示が行われる。表示されるコンテンツは Assets/Sample/Resources/tmpro.html 。


こんなのがでる。

スクリーンショット 2018-02-16 21.41.19.png

ちょっとだけシュッとしてるのがお分かりいただけるだろうか。


ズームして見るとuGUIとの違いがわかりやすい。

スクリーンショット 2018-02-16 21.43.34.png

テキストレイアウトの情報にもTMProのものを使っているので、字句の分割具合がuGUIと若干異なる。


あと左向き矢印とか出てない文字もあるんだが、これはフォントを作る時の範囲設定の問題。



簡単な使い方

0.unitypackage(https://github.com/sassembla/UUebView-freeversion/blob/TMProEnabled/UUebView.unitypackage)を対象プロジェクトに使う


1.表示領域となるRectTransformを持ったオブジェクトを用意。 例:uGUIのimageとか。不要なら画像消しちゃってOK。


2.そのオブジェクトにUUebViewComponent をセット。


3.適当なGameObjectを一つHierarchy上に作って、スクリプトを追加 + スクリプトにIUUebViewEventHandlerを実装する。

スクリプトはこんな感じ。https://github.com/sassembla/UUebView-freeversion/blob/TMProEnabled/Assets/Sample/SampleHandler3.cs

ずばり空のハンドラだけ。


4.UUebViewComponentのPreset Urlに、表示したいリソースのパスを、https:// とか、特殊なスキーマ resources:// で指定する。


5.UUebViewComponentのPreset Event Handlerに、3で作ったオブジェクトを指定する。



で、これをとりあえずサンプルリポジトリで実現したシーンを、SampleScene3として上げておいた。


インスペクター、実行時の見た目はこんな感じ。

スクリーンショット 2018-02-16 22.41.35.png

スクリーンショット 2018-02-16 22.41.51.png

、、、なんかロード完了時に親オブジェクト=baseの位置が動いちゃうのはバグだと思う。



独自タグの作り方

1.HierarchyのCanvas上に、cssファイルの名前をつけるような感じでRectTransformを持つ要素をセット。

2.この画像だとMyInfoViewって名前のRectTransformを持ったGameObjectを作成。

スクリーンショット 2018-02-16 22.45.14.png

ここで、MyInfoViewの子要素はすべてタグに変換される。

この絵だと、bgとかtitleBoxとかtextBgとか、titleTextとかがすべてHTMLタグに変形される。

許容されている要素は、Text、ImageなどのGUI要素と、それ以外のスクリプトなど。


3. bg/titleBoxなど、1階層以上ある構造部分は、「レイアウトのための情報」としての側面も持つ。

これらの要素は、自由にレイアウト制約をつけたり、背景画像を持ったり、テキスト情報を持ったりして良い。

レイアウトについて、

例えば<なんかタグ><titleBox>なにか要素</titleBox></なんかタグ>みたいに書くと、


なにか要素の部分のレイアウトは、titleBoxゲームオブジェクトが持っているuGUIのレイアウト特性を発揮する。

左からNドットとか、上下中央ぞろえとか、そういう特性を発揮する。


4.MyInfoView直下で階層を持たない要素は、レイアウトのための情報を一切保持しない。

画像コンテンツを置いた場合はその画角を維持したタグとして生成される。

これらの要素は、アンカー左上 + オフセットを左上とかにしておくと、動作時、ふつうのWebのレイアウトに近い感触になる。


階層ありのオブジェクトでレイアウトを指定し、階層なしのオブジェクトでコンテンツのスタイルを決定しレイアウトに打ち込む、

というのが基本スタイルになっている。


5.タグに変換する

というわけで、ここまでで作ったuGUIによるタグ集 MyInfoViewを選択した状態で、

Unity > Window > UUebView > Generate UUeb Tags From Selection

を押すと、選択していたオブジェクトはいい感じにHTMLのタグに変換される。


6.作ったタグを使ってみる

実際にMyInfoViewを使っているのがこのHTMLコード。

<!DOCTYPE uuebview href='resources://Views/MyInfoView/UUebTags'>

<body>

    <bg>

        <titlebox>

            <titletext>Sample</titletext>

        </titlebox>

        <newbadge/>

        <textbg>

            <textbox>

                <updatetext>lorem ipsum like sample. <br>← br here.<mya href='somewhere'>link here</mya> a long text will make large window. like this.<br> do you like hedgehog?</updatetext>

                <img src='https://pbs.twimg.com/profile_images/378800000220029324/fe66faeca20115da8566e51d83447ead_400x400.jpeg' button='true'/>

                <updatetext hidden='true' listen='readmore'>押したね! なんか出たね。<br>押されたらボタンの画像が動く、とかはUnityのアニメーションで簡単にできる。<br>今回はボタンを自由落下させる。</updatetext>

            </textbox>

            <showbuttonbg>

                <showbutton button='true' id='readmore'/>

            </showbuttonbg>

        </textbg>

    </bg>

    <bg>

        <titlebox>

            <titletext>日本語とか</titletext>

        </titlebox>

        <newbadge/>

        <textbg>

            <textbox2>

                <updatetext>日本語とかももちろん普通に入る。まだuGUIのデフォそのままなので、高さの問題とか改行がデリカシーないとかそのへんはあるんだけどね。たぶん。</updatetext>

            </textbox2>

        </textbg>

    </bg>

    <bg>

        <titlebox>

            <titletext>htmlから出してる</titletext>

        </titlebox>

        <textbg>

            <textbox3>

                <updatetext>このテキストやレイアウトの全てはSample/Resources/items.htmlっていうファイルから出している。もちろんhttpsとかで採ってくるのもできる。</updatetext>

            </textbox3>

            <iconbg>

                    <img src='https://pbs.twimg.com/profile_images/378800000220029324/fe66faeca20115da8566e51d83447ead_400x400.jpeg' button='true'/>

            </iconbg>

        </textbg>

    </bg>

    <bg>

        <titlebox>

            <titletext>ボタン?</titletext>

        </titlebox>

        <textbg>

            <textbox2>

                <updatetext>ある程度のwebサイト的な挙動を、htmlタグによる関連付けで動作するようにしてみた。簡単だけど動く。</updatetext>

            </textbox2>

        </textbg>

    </bg>

    <bg>

        <titlebox>

            <titletext>もっと高度なこと</titletext>

        </titlebox>

        <textbg>

            <textbox2>

                <updatetext>スターウォーズ好き? uGUIだから、ビューを回転させたりした状態でももちろんインタラクションするよ。</updatetext>

            </textbox2>

        </textbg>

    </bg>

</body>



HTMLなので可変長になるし、HTMLなのでタグで記述になるし、みたいな。


気になる内容は、、、?


<!DOCTYPE uuebview href='resources://Views/MyInfoView/UUebTags'>

1行目のDOCTYPEで、もはやHTMLではなくUUebViewだぜ、っていうのを高らかに宣言している。


で、このHTMLファイルで使っているタグデータはこれだぜ、みたいなのをリンクで書いている。

この書き方で、resourcesからMyInfoViewのデータを取り出し、以降使えるようにしている。


bgタグとかそういう元来HTMLに存在してなさそうなタグが跋扈してて平気なのはそのせい。


ちなみにaタグとかpタグとか、さすがにこれはデフォルトで合った方がいいよね?みたいな要素は、

デフォルトが用意されていて暗黙的に使えるようになっている。また、それらの設定も変更できる。


resources://みたいなプロトコルを勝手に定義しているが、これを、例えば外部からデータを持ってくるプロトコルに変えるとどうなるか、、?

ビューに表示するすべてのレイアウト要素、スタイル要素を更新することができる。


ちなみにAssetBundleをDLしてきてロードするみたいなの途中まで作っててまだ完成してない。


imgタグなどの画像タグ(imageコンポーネントを持った状態でGenerateされたタグ)は、hrefでresources://とかhttps://とか書いて

好きなところからデータを取得することができる。



UUebViewからTMProを使うには

SampleScene2ではすでに条件が整えられた状態になっているので、新規プロジェクトにunitypackageとかで放り込む場合には解説が必要。


手順はまだちょっと複雑で、

1.TMProを入れる

2.UUebView/UUebViewPlugins/フォルダ内のTMProPlugin.cs.gzをその場に解凍する

3.UUebViewのインスタンス作成時、次のようなコードを書く。

uuebView = UUebViewComponent.GenerateSingleViewFromUrl(this.gameObject, "resources://tmpro.html", scrollViewSize, null, null, null, null, new TMProPlugin());

以上。


ものすごくかっこ悪い状態なんだけど、末尾のnew TMProPlugin()で、TMPro対応のプラグインを入れてる。

そのうちもうちょっとカッコよくなる。多分。



ひとまずこんな感じ。WebGLビルドでブラウザで見ても字が綺麗。これはモチベーション上がるわ。




wrote 2018/02/16 15:34:10

Autoyaについてのドキュメント更新の前のウォーミングアップ


概要

Autoyaのドキュメントは2018に入ってから更新が止まっていてやばい。

最新で異様な機能が入っていたりするのでせめてその部分の更新をしないといけない。


あとなんかOSSドキュメントについていい感じのツールがあった気がするので漁ってみたい。


まずはメモを残す。


AssetBundle、Information、Manifest、OverridePoints



AssetBundles

基本戦略

Autoyaで実装されているAssetBundleの使用法は、オンデマンドなタイミングでのロード(必要であればABのダウンロードを含む)と、Preloadの2つに分かれる。

依存性解決あり。


Preloadは「使う前にAssetBundleをDLしておく」機能になっていて、PreloadListというjson形式のデータで「このシーンに入ったら最低限DLしておいてほしいABはこれ」とか

指定してDLさせることができる。


ちなみにPreloadListは何個、どんな分割で作ってもいい。


また、高度な使い方として、PreloadListの代わりに「サーバからPreloadListをダウンロードできるurl」を書くことができ、

ゲーム運営が進んだタイミングでサーバが返すデータを更新することで、「この画面まできたらあるABを全ユーザーが保持している見通しがあるのでダウンロードさせておく」などができる。


これによってサーバ側でユーザーが保持しているABのダウンロードタイミングを完全に制御することができる。



AssetBundleListとAssetGraphとの連携

AssetBundleListは、Autoyaで扱うABのリスト。json形式で、サーバから返したり初期バージョンをアプリケーションに入れておいたりできる。

ABListは運用に起因するリソース更新に応じて更新される。更新系はAutoyaのネットワークハンドリング起因でイベントとして発生し、かなりかっこいい実装になっている(雑)。


どこかのバージョンから、AssetGraph v1.3を同梱したUnityPackageを配布するようになった。

これにより、AssetGraph から AssetBundleList + AssetBundles の生成が可能になっている。


AssetGraph側のこの辺変えたいな~みたいな要素もちょこちょこあるのでそれはまた別に記載する。



AssetBundleListのマルチ化

要望としてちょいちょい上がっていた、AssetBundleListのマルチ化 = 複数リストでの運用に対応した。


これによって、AssetBundleを複数のリストに分け、管理/更新することが可能になった。

例えばアドベンチャーパートのABはめっちゃ更新頻度が高いんだけど他は別に、、みたいな時、Adv用のABListとそれ以外用のABListを別に更新したりできる。


トピックとしては簡単なんだけど実用には根本的にいろんな方面の難易度がある。


・使用できるAssetBundleListの情報はRuntimeManifestに記述する必要がある(リストの名前、ver、ダウンロードurlベースパスなど)

・サーバがクライアントのリソースを更新したくなったら、レスポンスヘッダーに特定の値を入れることでリストの更新を促すことができる。つまるところサーバドリブン。

・CDNにいろんなパスを掘ってAssetBundleを安置しておく必要がある

など。

マルチになったABList自体の作成はAssetGraphに依存していて、


AssetGraph Aを作る -> 

AssetGraphのハンドラにAutoya用のスクリプトアタッチする -> 

ビルド -> 

Aという名前のABList + ABが、プラットフォームやバージョンを加味された状態で生成される 


という流れになっている。



というかこれをAssetGraph使わずに人間が作るのは、APIを叩くだけにしたってほんとうにしんどい。仕様的に一つしか正解APIがないし、そのAPIは本当にメジャーじゃないし。


そのAPIって?

これ。

http://sassembla.github.io/Public/2016:08:22%2015-13-26/2016:08:22%2015-13-26.html


このAPIを人間が手で書いて使うのは無理。AssetGraphはその内部でこれを使っている。

AssetDatabaseの状況に左右されず、EditorのassetBundleドロップダウンを一切無視した状態で、manifestファイルを無制限に複数生成できる。



Information


お知らせ画面

Autoyaの中の特異点、ヤッチマッタ感の高いフルスクラッチUnityネイティブなWebViewでのお知らせ画面表示機能がある。

uGUIでHTMLタグを作って、HTMLを書くとそのレイアウトやConstraint、uGUIについてるスクリプトをバッチリ使用できる。


圧倒的にWebViewより高速で、メモリも食わず、コントロール感覚はUnityそのもので、全プラットフォームで動かせる。


HTMLタグ自体も外部からAssetBundleやらで輸入できるため、ぶっちゃけWebComponentsみたいなものをUnity上で実装したという表現があってる。

やりすぎた。


まだ完全じゃないので、無理して使わないでいいと思う(及び腰)


TextMesh Pro対応がもうすぐリリースされるので、そうすると態度でかくなると思う。すごく綺麗かつ高速。



Manifest


宣誓書

Autoyaでは、ビルド時に確定してブレない情報と、実行時に動的に更新されるような情報をManifestという形式で保存している。

BuildManifestとRuntimeManifestがそれ。


BuildManifestにはみんな大好きビルド番号や日時、constなデータなどをビルド時に書き込むことができ、これは不変になる。

RuntimeManifestには現在保持しているABListの情報などを入れることができ、永続化対象にもなっている。

Autoya.Manifest_なにやらで出てくる。


これらManifestのファイル内容は本来開発者が自由に書いていいと思っているんだけれど、

ABListのマルチ化に伴って「これは一体なんなんだ?」的なデフォルト設定がうまれてしまっているのがとてもまずいと思っている。



OverridePoints


上書き可能なポイント集

Autoyaではそのデフォルトの挙動でJWTでの認証や改ざん防止を放り込んであって、

それらのパラメータや動作はすべてOverridePoints.csというファイルを更新することで変更できる。


Frameworkとしての指針は、

「フローは決まってるんでどんなプロトコル使うかとかどう暗号化してファイル保存しようかは各自頑張って」

である。

んでその、OverridePointsがちょっと増減してるはずなので、それを書かねば。



wrote 2018/02/15 13:21:31

Unityでプラグイン機構を持ったdllを作る


概要

次のような前提の時に使えるテクニック。


・dllにして配布するAssetを作る

・プロジェクト内に特定のdllがある場合、それを本Assetから拡張機能として使う


例えば、「もしAっていうライブラリがあったら、それを使った拡張機能を有効にする」みたいなやつ。

これは変則的だけど、「他のライブラリをプラグインのように扱う」ってことになる。



具体例

UUebViewっていうAsset作って使ってるんだけど、デフォルトではuGUIのテキストを使ってUIを生成している。


で、まあ、テキストといえばTextMesh Pro(TMPro)で、そっち使った方が綺麗なUIになるんだよね。

なので、TMProを使った描画機能を提供したい。


TMPro、予定ではUnityに組み込まれ中というステータスなんだけど、現状ではまだ含まれていない。

AssetStoreで無料で取得できるけど、勝手にプロジェクトにdllを組み込むわけにはいかない。


よって、次のような条件が存在する。

1.TMProがあったらTMProの機能を使って描画する機能がOnになる

2.verとか重複で絶対困るので、TMProのdllを組み込んで配布するわけにはいかない = AssetのdllにTMProを含めてはいけない

3.TMProがなかったらその機構は使えないが、それはそれとしてuGUI Textが使えるので単体でビルドできないといけない

4.できるだけコンパイル時にTMProを使うかどうかの選択を完了させたい。


つまり、TMProを含まず、TMProが場にあった場合にはそちらに接続することができ、

TMProがない場合でも動作してほしくて、コンパイル時には何を使うか確定していると楽。



叶え方

真面目にリフレクションなどで実行時にガンバるみたいな手もあったんだけど、できるだけコンパイル時に完了させたい。

ということでこんな感じにすればできるよ的な。



・本体コード -> 依存対象dllへの依存があるコードを書く

・依存対象dllを一旦削除し、依存対象dllに入っていた部分をダミーコードとして実装する

・ダミーコードを依存対象と同じsignatureでdllにする(ダミーdllの生成)

・ダミーdllを参照する形で本体コードをdllへとコンパイル(本体dllの生成)


これで、ダミーdll = 依存対象dll という関係が成立し、本体dllからは、ダミーdllと依存対象dllの区別はつかず、

依存対象dllの機能を本体dllから使いたい場合は、ダミーdllを削除 & 依存対象dllをコンパイルに巻き込めばOK という形になる。


問題点

TMProのdllのsignatureが最悪で、次のような値になっている。


Assembly TextMeshPro-2017.2-1.0.56-Runtime, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null


nameにversion値が書いてあるんで頭を抱えている。

これ新version出たらdllのsignature変わってしまうので、適合性が消えてしまう。


で、これはまあ対処法としては、本体dllに記載されている「こんな名前のdllに依存してます」みたいな情報を書き換えるとできる。

その機能をポータブルに提供できれば、完璧なのだが。


まだそこまでは踏み込んでいない。


いろいろ解決できたらさらに図を足す。



wrote 2018/02/08 0:18:21

Akeytsuでボーン+リギング 操作法 ver1.x


概要

Steamで発売してて手軽に買えるようになったねAkeytsu!

で、1.x系はちょいちょいUIが変わってるので書き直すぞ。



概念

・ジョイント(ボーン)を追加することができる

・モデルに対してジョイントをセット(bind)することができる(Skinning)

・モデルに対してジョイントをbindするとバンクにBind Poseが生成される

・モデルに対して、ボーンの追従度をセットすることができる



ざっくりした操作方法

1.ボーンを作る

2.ボーンを選択状態にする -> モデルを選んでbindする

3.ボーンに対してメッシュへの影響度合い荷重を割り当てる

4.モーションを作る


ところでAkeytsuにはUnity用のboneがデフォルトで用意されてるので、これは良いぞ。

u.png



1.新規にボーン(ジョイント)を作る

1.JOINT ウィンドウのCreateボタンを押し(or Jキーを押す)、画面のどこでもいいのでクリックすると、最初のボーンが作られる。

2.マウスを適当に動かした状態でクリックすると、先ほどのボーンと連続した新しいボーンが作られる。

これ以上ジョイントを作成したくない場合、JOINTウィンドウのCreateボタンを再度押す(or Jキーを押す)と、生成が止まる。

2.ジョイントを選択状態にする -> モデルを選んでbindする

v1.0.3からGUIが変わった。


0.CHARA BANK > 対象のキャラクター選択 > Skin & Checkを選択

1.PICKERから対象のボーンを選ぶ

2.shiftキーを押した状態で、TREE > 紐づけたいメッシュを選ぶ

3.SKIN ATELIER > +1ボタン でBind 開始

4.+2ボタンでBind完了。

以降、メッシュはボーンに従属するようになり、各ボーンに対してどれかのメッシュについての荷重をセットすることが可能になる。



メッシュの選択と荷重のセットのTips

SKIN ATELIERの機能がそのセットになっている。

・ボーンに対してbindしたメッシュ群の中でどのメッシュがどのボーンからどの程度影響を受けるかを設定できる。


・aキーでブラシモードに突入、再度aキーを押すとブラシモード解除。ブラシモード中はカメラを動かせない。


・ブラシツールではWeightやStrength、Sizeを変更しながらブラシで塗るように影響度をセットできる。ブラシなので表面のみを編集でき、裏まで貫通しない。


・右クリックで荷重のadd、左クリックで荷重のremoveができる。


・変更するときは、TREE > 各パーツを右クリックで、Lock Skin Weight とかを行うと、対象範囲だけをいじれて便利。ショートカットないのかな、、、


・途中でボーンの位置が気に食わなくなった場合、CHARA BANKのBind Poseを選択した状態でボーンの位置を動かすと、既存の荷重設定の影響を受けずにすむ。

ボーンの基本位置を編集するときはBind Pose、荷重を編集するときはSkin & Checkという切り分け。


・shiftを押しながらクリックでポイント選択、shift + dragで範囲選択、これはブラシと違い、裏表を関係なく貫通する。


・選択した状態の頂点に対して、SKIN ATELIERの縦長のボタンや、その右の荷重値ボタンを押すことで荷重を当てることができる。


・荷重が当たる対象はSKIN ATELIERウィンドウ下のボーン一覧で選択中のものになるので、複数ある場合は荷重を分散できる。


・ブラシのWeightやStrengthを下げることでグラデーション的に荷重をセットできるので、調整が簡単。


・CHARA BANK のSkin & Check選択時は各ボーンの回転や移動を0にすると Bind Pose 選択時の姿勢と一致するので、

Skin & Checkモードでボーンを動かしながら荷重を変更 -> 位置や回転に0を入れて姿勢を戻す といったことができる。大変便利。



荷重を付ける際の制約(MUST)

・すべての頂点は最低でも一つのジョイントの影響下にあること

みたいな制約がある。その制約を守らないと、頂点に振ってある荷重をゼロにすることができず、意図せず動いてしまう、みたいなことが起きる。

・これを満たすために、ボーンに対してメッシュをbindする際、root以外のboneを選択 -> メッシュを選択してbindすると、rootの一つ下のボーンにすべてのメッシュが荷重された状態になるので、楽。

v1になった時にこの「すべての荷重がbindした一番上のボーンに自動的にかかる」挙動になったようで、楽になった。

wrote 2018/01/25 19:43:37

Tsuke デザインドキュメント


概要

Tsuke(ツケ)は、デザイン時などに発生するバイナリファイルをいい感じに時間単位などで別名保存し、あわよくはワークフローに乗せてくれるツール。

みなさんのツケはTsukeが払う。


Tsuke

https://github.com/sassembla/Tsuke/tree/master


デザイン

アプリケーションとしては、特にDropBoxの共有フォルダの中で働くと最高の仕事をするようにしたい。

・進捗があれば、時間につき1つのコピーを生成する

・コピー後、レシピを実行する(あれば)



時間設定

まずは直書きで、1時間に一度、ファイルの更新具合を確かめてファイルコピーの有無を考える。

コピー先は内部のファイル置き場で、フォルダ名に応じてhashを生成する。

監視対象のパスがwin/macで異なると困る? 別に困らんよな。対象となるファイルが存在しなければ何もしない。

コピー先はどうする?

日付、時間ごとにフォルダを切りたい。

YYYY_MM_DD_hh あたりがパス候補。

一覧することを考えると、identity/YYYY_MM_DD_hh/ファイル となるのが嬉しい。ファイル名は変えない。


ハードコピーの悪夢をどう避けるか

まんますべてのファイルをコピーすると、容量がすごいことになる。というかなった。

で、変更部分のみをアレする + 全体を取り出したい場合はここ、みたいなフォルダを用意するといいかもしれないと思った。


まだ手をつけてない。


・レコード一件につき更新があったファイルしか入っていない

・取り出したいフォルダの何かをアレすると全体が取り出せる

うーん、shadowファイルつくるか、最新コピーを完全な形で持つフォルダを一つつくるか。悩みどころ。

とりあえず実用に耐えているので、まずはこのままで。


最大重量を作って超えたら消すみたいなのでもいいかもしれない。





wrote 2018/01/21 22:04:02

ZBrushのスクリプト Zscriptを書いて動かす


概要

VRでモデリングしてそいつをいい感じにリトポしたりするのにZBrushを使ってるんだけど、

VR側のモデリングでかなり精度を出せるようになってきたので、ZBrushでやる作業がほぼリトポだけになってきた。


で、これをいちいちモデルの全パーツに対してやってるのがしんどくなってきたので、Zscriptを書いてZBrushの動作を自動化しようみたいなはなし。



Zscriptって何

リファレンス

http://docs.pixologic.com/user-guide/customizing-zbrush/zscripting/technical/


なんというかスクリプトで、ZBrushの動作を記述してloopとかifでサブツール(ZBrushのオブジェクト単位)に対して操作を加えることができる。

もっと簡単に言うと、ボタンを増やしてそのボタンを押したらどうなるかを作成できる


動かし方

1.ZBrush > Zscriptメニュー > Record > なんか適当に自動化したいことをする > Zscriptメニュー > End Rec で、動作内容をテキストファイルとして出力できる

その際、「初期化する?」とか聞くダイアログが出るんだけど、対象モデルを用意した上でYesとか押すと対象モデル搔き消えるんで、断固Noを押すケースの方が多いと思う。

スクリーンショット 2018-01-19 22.26.19.png

2. 1で吐き出したtxtとにらめっこしながらスクリプト(txt形式)を書く。

<このときコツというか言外の仕様がいくつかある。後述>


3.書いたスクリプトを、ZBrush > Zscriptメニュー > Load で読み込む。

このとき、UIがこんな感じになっていることを確認しとく。

スクリーンショット 2018-01-19 22.24.11.png


4.なんか実行できないエラーがあったら画面下部のところに赤く表示される。

これ困ったことにテキストではなく映像としてエラーが表示されるんで、エラー内容ググるのが大変だった。


5.実行できる場合、ボタンが画面下部のところに表示される。このボタンを押すと、Loadしたスクリプトが実行される。

スクリーンショット 2018-01-19 22.22.19.png

言外の仕様

ドキュメント見ても書いてなかったと思うんだけど次みたいな仕様があった。


・コメントで日本語を書くのはOK、ただし、Noteなどのメッセージを出す画面では英語以外表示されない

はい。

ちなみにMacroってメニューだとコードにコメントを書くこと自体が不可


・エラーにならないケースがある

どうもメッセージングみたいな挙動をしていて、

・メソッドの引数の型が合わない場合はエラー

・メソッドの引数の内容が見つからない場合はエラー


これらはちゃんとエラーになるんだけど、次のケースはエラーが出ない。

・IPressで存在しないコマンドを実行する

これが結構厄介で、ZBrush自体がRecordで記録するコマンドが間違ってるケースがちょいちょいあるみたいで、

存在しないコマンドを実行することになってしまい、これがエラーを吐かないので停止せずエライことになる。


・continueやskipみたいな概念がない

Loopっていう他言語でのforみたいなのがあるんだけど、これがifでskipしたりcontinueしたりできない。

つらい。



最低限これだけ使えれば試行錯誤できそうなコマンド


Note

[Note, "English!!! only!"]

画面上にメッセージを出す。このままだとクリックしないと消えない。今変更を加えようとしているSubToolがどれなのか、とか

そういったデバッグのための情報を知るのに重宝する。

VarDef, VarSet

[VarDef, 変数名, 初期値]

[VarSet, 変数名, 値]

変数定義と定義済み変数への値の上書きを行う。

値には数字、文字列、リスト(値 or 文字列)がある。


SubToolSelect

[SubToolSelect, 数字]

特定の番号のSubToolを選択した状態にする。後述のLoopと組み合わせると、全てのSubToolに対して何かする、みたいなのが

簡単にできる。


Loop

[Loop, 回数, 処理, インデックス変数]

回数文だけ処理を実行する。


インデックス変数は処理の中で使うことができる。例えば次のようなコードの場合、

// 場にあるSubToolの数を変数 subToolCount にセット

[VarSet, subToolCount, [SubToolGetCount]]


[Loop, subToolCount, 

// 上からn番目のツールを選択した状態にする

[SubToolSelect, [Val, n]]

,

n

]

subToolCount回数ぶん、処理 上からn番目のツールを選択した状態にする を実行する。

その際、nには0 ~ (subToolCount -1)までの数字が入る。


nを取り出すのに[Val, n] とか書かなきゃいけないのがなんともキツイが、これは有効に動作する。

これだけで場にあるすべてのSubToolを順に選択することができる。


ZBrushでは選択状態のSubToolに対して何か処理を加える、というのが根幹的な動作になっているので、

選択できさえすればあとは動作をさせればいい感じになる。


IGetTitle

[IGetTitle, Tool:Current Tool]

現在選択されているSubToolの名称を取得する。

このメソッド と 文字列を足すメソッドを組み合わせることで、順番以外の方法でSubToolを指定することが可能になる。

具体例は次。


StrMerge

[StrMerge, "Tool:Sub Tool:", #currentSubToolName]

こんな感じに書くと、変数 currentSubToolName に入っている文字列と、文字列 Tool:Sub Tool: を連結する。

例えば currentSubToolName に A とか入ってたら、Tool:Sub Tool:A が出力される。


VarSetとかと組み合わせて、Tool:Sub Tool:ツール名 みたいな文字列を変数に入れておくことができる。


これがあると、次のような動作が自動化できる。


IModGet, IModSet

[IModSet, currentSubToolPath, [IModGet, currentSubToolPath] + 32]// set visible.

名前で指定したUIのパラメータを変更する。 Getで取得、Setでセット。

例えば上のコードで、currentSubToolPathに書かれているSubToolの表示/非表示を切り替えられる。


このモード値みたいなやつはイマイチよくわかってない。書き方によっては再現性がなかったりする。

この関数では、特定のSubToolの指定を文字列で行なっているんだけれど、SubToolを文字列から指定する場合、

Tool:Sub Tool:ツール名 みたいな文字列にならないと指定できない。なぜこんな、、まあ、、、はい、、、


以上のコマンドと、あとはZscript > Record からの動作 -> サンプルコードが出てくるのでそれらを抜粋、、 をいい感じにやると、

比較的なんでも自動化できる気がする。



注意点

たいへんとっつきにくい要素がこれらだった。いまならもう怖くない、、


・Top Levelという概念

Zscriptに記述できる一番外側のブロックをTop Levelといい、UIに関係するコードや変数定義、関数定義などを記述することができる。

このレベルにダイレクトにLoopとかIfとかの処理を書くことはできない。

処理を書く場合、必ず ボタンを押したら~ みたいな関数の中に書く必要がある。



・Zscript > Record は時々嘘をつく。

例えば Record中に Tool > Geometry > Modify Topology > Delete By Symmetry とかを実行すると

[IPress,Tool:Geometry:Delete By Symmetry]


とか記録されるんだけど、これをそのままコピーしてもDelete By Symmetry は実行されない。 ええ、、、

そう、記録されたコマンドが間違っている。


正しくは、

[IPress,Tool:Geometry:Modify Topology:Delete By Symmetry]


まあ手で実行するときの階層がそうなってるんで、、まあ、、、はい、、、なんで間違うの、、、? バグ、、、?



・変数の寿命が独自

[VarDef, A, "initial"] みたいな感じで変数を初期化、

[VarSet, A, "set"] みたいな感じで変数に値を代入できるのだけれど、


VarDefはTopLevel(すべての関数の外側)にしか書けない。


loop関数の中でVarDefを使うと、挙動がおかしくなる。 具体的にはAが定義済みの場合は[VarDef, A....]は定義を上書きしないみたいだ。

なので、プログラム中で変数として使いたい値がある場合、プログラムの上の方にまとめてVarDefしておく必要がある。


もしくはダイレクトにVarSetだけ使うとか。



感想

いままでいろんな言語扱ってきたけど、そのなかでも一番辛かった。でもこれで自動化できる!! 効率最高になった。


wrote 2018/01/19 22:12:27

BenchmarkDotNetでDisquuunをチューニングした時のメモ


概要

とりあえず適当に。



デフォ


BenchmarkDotNet=v0.10.11, OS=macOS 10.12.6 (16G1114) [Darwin 16.7.0]

Processor=Intel Core i7-7Y75 CPU 1.30GHz, ProcessorCount=4

.NET Core SDK=2.0.0

  [Host]     : .NET Core 2.0.0 (Framework 4.6.00001.0), 64bit RyuJIT

  DefaultJob : .NET Core 2.0.0 (Framework 4.6.00001.0), 64bit RyuJIT


Method

Mean

Error

StdDev

Take10Connection

74.96 us

1.449 us

1.355 us



適当に数回動かす。


                   Method |     Mean |    Error |   StdDev |

------------------------- |---------:|---------:|---------:|

  Take_10byte_2sock_async | 68.04 us | 28.83 us | 1.629 us |

 Take_10byte_10sock_async | 72.87 us | 22.36 us | 1.263 us |

 Take_10byte_30sock_async | 73.63 us | 29.12 us | 1.645 us |



                   Method |     Mean |    Error |    StdDev |

------------------------- |---------:|---------:|----------:|

  Take_10byte_2sock_async | 74.89 us | 16.02 us | 0.9051 us |

 Take_10byte_10sock_async | 68.70 us | 36.14 us | 2.0421 us |

 Take_10byte_30sock_async | 70.65 us | 42.91 us | 2.4246 us |


2018/01/13 5:32:34




2018/01/13 5:32:40


                   Method |     Mean |     Error |    StdDev |

------------------------- |---------:|----------:|----------:|

  Take_10byte_2sock_async | 74.17 us | 1.4725 us | 2.1118 us |

 Take_10byte_10sock_async | 74.60 us | 0.9152 us | 0.8113 us |

 Take_10byte_30sock_async | 75.57 us | 0.8857 us | 0.8285 us |


フル版、若干高速化できた気がする。まだ気分だけ。


                   Method |     Mean |    Error |    StdDev |

------------------------- |---------:|---------:|----------:|

  Take_10byte_2sock_async | 74.52 us | 1.022 us | 0.7979 us |

 Take_10byte_10sock_async | 75.39 us | 1.079 us | 1.0091 us |

 Take_10byte_30sock_async | 78.41 us | 1.518 us | 2.2717 us |



                      Method |     Mean |    Error |    StdDev |

---------------------------- |---------:|---------:|----------:|

     Take_10byte_2sock_async | 141.5 us | 282.3 us | 15.949 us |

    Take_10byte_10sock_async | 143.5 us | 235.4 us | 13.298 us |

    Take_10byte_30sock_async | 167.5 us | 545.8 us | 30.840 us |

  Take_10byte_2sock_pipeline | 138.9 us | 134.2 us |  7.584 us |

 Take_10byte_10sock_pipeline | 140.2 us | 175.1 us |  9.892 us |


ubuntu関係なく動かして検証できそう。


                  Method |     Mean |     Error |    StdDev |

------------------------ |---------:|----------:|----------:|

  Take_10byte_2sock_sync | 52.78 us |  7.275 us | 0.4111 us |


tcpを扱うライブラリなので、基礎的なsyncはまあそのまま速度が計測できるんだけど、asyncの負荷を測るには、というのがまだ正しくない。

内部的な機構の速度を計測するようにしよう。



遅そうなところでいうと、複数のソケットを切り替えるあたり。

lockを外すことができたら結構変わるのでは感

参考

http://engineering.grani.jp/entry/2017/07/28/145035


hashtable良さそう。


                      Method |      Mean |     Error |     StdDev |

---------------------------- |----------:|----------:|-----------:|

     Take_10byte_2sock_async |  68.21 us |  10.81 us |  0.6107 us |

      Take_10byte_2sock_sync |  64.78 us |  53.97 us |  3.0491 us |

    Take_10byte_10sock_async |  94.92 us |  43.23 us |  2.4424 us |

    Take_10byte_30sock_async | 109.56 us | 418.98 us | 23.6731 us |

  Take_10byte_2sock_pipeline | 102.49 us |  83.99 us |  4.7454 us |

 Take_10byte_10sock_pipeline |  76.44 us |  33.99 us |  1.9203 us |

 Take_10byte_30sock_pipeline |  77.62 us |  91.14 us |  5.1495 us |


pipelineが割と高速な気がするのはいいこと。



とりあえずあと追加すべきなのは

・足りない場合のソケット追加アラート

stackに入った時間とstackしてたものが取り出される時間で、その時間の最長を残す? 失速していた時間、みたいな。

単位時間あたりの失速回数とかでもいいのかな、スレッド使うの嫌だから、発生タイミング関連でなんかできるといいのだが


                      Method |      Mean |     Error |     StdDev |

---------------------------- |----------:|----------:|-----------:|

     Take_10byte_2sock_async |  69.06 us |  23.87 us |  1.3487 us |

      Take_10byte_2sock_sync |  56.41 us |  14.25 us |  0.8050 us |

    Take_10byte_10sock_async |  69.36 us |  38.55 us |  2.1779 us |

    Take_10byte_30sock_async |  72.14 us |  33.17 us |  1.8742 us |

  Take_10byte_2sock_pipeline |  75.60 us |  29.17 us |  1.6484 us |

 Take_10byte_10sock_pipeline |  77.12 us |  10.02 us |  0.5662 us |

 Take_10byte_30sock_pipeline | 103.12 us | 196.04 us | 11.0764 us |



-> available(ソケットプールからの使用可能ソケットの抽選)の書き方変えられるかも。わざわざsocketまで読みにいかなくてもいい的な。

やってみた -> 


                      Method |     Mean |     Error |    StdDev |

---------------------------- |---------:|----------:|----------:|

     Take_10byte_2sock_async | 81.98 us | 101.04 us |  5.709 us |

      Take_10byte_2sock_sync |       NA |        NA |        NA |

    Take_10byte_10sock_async | 91.41 us | 157.85 us |  8.919 us |

    Take_10byte_30sock_async | 95.51 us |  80.68 us |  4.558 us |

  Take_10byte_2sock_pipeline | 99.40 us | 285.53 us | 16.133 us |

 Take_10byte_10sock_pipeline | 85.39 us | 145.92 us |  8.245 us |

 Take_10byte_30sock_pipeline | 76.18 us |  36.68 us |  2.072 us |


遅くなったw

やーめよ。


                      Method |     Mean |     Error |    StdDev |

---------------------------- |---------:|----------:|----------:|

     Take_10byte_2sock_async | 78.41 us |  44.05 us |  2.489 us |

      Take_10byte_2sock_sync | 57.63 us |  28.17 us |  1.592 us |

    Take_10byte_10sock_async | 76.53 us |  33.12 us |  1.871 us |

    Take_10byte_30sock_async | 83.94 us |  28.41 us |  1.605 us |

  Take_10byte_2sock_pipeline | 85.94 us |  97.83 us |  5.527 us |

 Take_10byte_10sock_pipeline | 84.15 us | 233.62 us | 13.200 us |

 Take_10byte_30sock_pipeline | 84.44 us |  18.17 us |  1.027 us |



パイプライン系に10倍のデータを流すベンチを追加。まとめて送る系の効果はデータ量に対してしっかりと出る。


                      Method |      Mean |      Error |     StdDev |

---------------------------- |----------:|-----------:|-----------:|

     Take_10byte_2sock_async |  81.15 us |   9.596 us |  0.5422 us |

      Take_10byte_2sock_sync |  59.28 us |   5.387 us |  0.3044 us |

    Take_10byte_10sock_async |  99.69 us | 223.154 us | 12.6086 us |

    Take_10byte_30sock_async |  78.28 us |  36.978 us |  2.0893 us |

  Take_10byte_2sock_pipeline | 152.23 us |  40.314 us |  2.2778 us |

 Take_10byte_10sock_pipeline | 156.67 us |  80.243 us |  4.5339 us |

 Take_10byte_30sock_pipeline | 184.29 us | 272.888 us | 15.4187 us |


conoha上のubuntu 4コアで実行したところ、こんな感じ。


                          Method |      Mean |      Error |    StdDev |

-------------------------------- |----------:|-----------:|----------:|

         Take_10byte_2sock_async | 111.04 us |   131.1 us |  7.406 us |

          Take_10byte_2sock_sync |  80.81 us |   108.5 us |  6.132 us |

        Take_10byte_10sock_async | 130.34 us |   304.1 us | 17.181 us |

        Take_10byte_30sock_async | 116.58 us |   310.2 us | 17.529 us |

   Take_10byte_2sock_sync_10item | 895.81 us | 1,387.7 us | 78.405 us |

 Take_10byte_10sock_async_10item | 343.30 us |   582.9 us | 32.935 us |

 Take_10byte_30sock_async_10item | 373.80 us |   321.7 us | 18.178 us |

      Take_10byte_2sock_pipeline | 131.05 us |   168.6 us |  9.528 us |

     Take_10byte_10sock_pipeline | 129.62 us |   244.6 us | 13.823 us |

     Take_10byte_30sock_pipeline | 134.58 us |   187.4 us | 10.586 us |

   Take_10byte_2sock_pipeline_10 | 299.17 us |   413.9 us | 23.386 us |

  Take_10byte_10sock_pipeline_10 | 273.35 us |   382.1 us | 21.588 us |

  Take_10byte_30sock_pipeline_10 | 298.77 us |   276.1 us | 15.601 us |


こんな感じか。

async系は軒並みWaitHandleのペナルティを負ってるんで、それでこのスコアならいい感じなのでは。


ここで、tcpソケットを実用しない、ロジックのみの実装版が完成。

ほぼ何もしないソケットだと動作速度はこんな感じ。



                          Method |      Mean |      Error |    StdDev |

-------------------------------- |----------:|-----------:|----------:|

         Take_10byte_2sock_async |  4.018 us |  1.2750 us | 0.0720 us |

          Take_10byte_2sock_sync |  1.500 us |  0.2568 us | 0.0145 us |

        Take_10byte_10sock_async |  4.180 us |  0.6578 us | 0.0372 us |

        Take_10byte_30sock_async |  4.136 us |  0.6864 us | 0.0388 us |

   Take_10byte_2sock_sync_10item | 14.721 us |  3.6871 us | 0.2083 us |

 Take_10byte_10sock_async_10item | 17.819 us |  4.7120 us | 0.2662 us |

 Take_10byte_30sock_async_10item | 18.440 us | 12.3032 us | 0.6952 us |



さらにloopとかを加えられるようにした。


うーんベースクラス用意するとベンチが覿面に落ちるのなんで。interfaceにしてみるか。


                          Method |      Mean |       Error |     StdDev |

-------------------------------- |----------:|------------:|-----------:|

         Take_10byte_2sock_async |  4.263 us |   1.6034 us |  0.0906 us |

          Take_10byte_2sock_sync |  1.572 us |   1.3900 us |  0.0785 us |

        Take_10byte_10sock_async |  4.242 us |   1.0398 us |  0.0588 us |

        Take_10byte_30sock_async |  4.183 us |   0.6072 us |  0.0343 us |

   Take_10byte_2sock_sync_10item | 15.413 us |   3.4801 us |  0.1966 us |

 Take_10byte_10sock_async_10item | 18.348 us |  11.8447 us |  0.6692 us |

 Take_10byte_30sock_async_10item | 18.033 us |   0.7730 us |  0.0437 us |

      Take_10byte_2sock_pipeline |  4.753 us |   0.7805 us |  0.0441 us |

     Take_10byte_10sock_pipeline |  4.670 us |   0.8726 us |  0.0493 us |

     Take_10byte_30sock_pipeline |  4.529 us |   0.5373 us |  0.0304 us |

   Take_10byte_2sock_pipeline_10 | 25.391 us |   5.5216 us |  0.3120 us |

  Take_10byte_10sock_pipeline_10 | 24.981 us |   5.8046 us |  0.3280 us |

  Take_10byte_30sock_pipeline_10 | 23.549 us |   7.6720 us |  0.4335 us |

        Take_10byte_2sock_loop_2 | 33.197 us |  11.0151 us |  0.6224 us |

       Take_10byte_10sock_loop_2 | 55.504 us | 398.8342 us | 22.5349 us |

       Take_10byte_30sock_loop_2 | 43.701 us | 391.8285 us | 22.1390 us |


さらに落ちた。

まあ、メンテナンス性考えたらこんな感じかな~と思いつつ、遅い。


                          Method |      Mean |     Error |    StdDev |

-------------------------------- |----------:|----------:|----------:|

         Take_10byte_2sock_async |  5.246 us |  9.635 us | 0.5444 us |

          Take_10byte_2sock_sync |  1.737 us |  1.059 us | 0.0598 us |

        Take_10byte_10sock_async |  4.994 us |  5.007 us | 0.2829 us |

        Take_10byte_30sock_async |  5.447 us |  6.660 us | 0.3763 us |

   Take_10byte_2sock_sync_10item | 16.707 us |  5.224 us | 0.2952 us |

 Take_10byte_10sock_async_10item | 18.547 us |  9.683 us | 0.5471 us |

 Take_10byte_30sock_async_10item | 18.483 us |  7.964 us | 0.4500 us |

      Take_10byte_2sock_pipeline |  5.722 us |  6.309 us | 0.3565 us |

     Take_10byte_10sock_pipeline |  4.856 us |  4.104 us | 0.2319 us |

     Take_10byte_30sock_pipeline |  5.816 us |  3.047 us | 0.1721 us |

   Take_10byte_2sock_pipeline_10 | 29.869 us | 42.256 us | 2.3876 us |

  Take_10byte_10sock_pipeline_10 | 25.101 us |  3.782 us | 0.2137 us |

  Take_10byte_30sock_pipeline_10 | 24.649 us |  3.549 us | 0.2005 us |


戻した。


                          Method |      Mean |      Error |    StdDev |

-------------------------------- |----------:|-----------:|----------:|

         Take_10byte_2sock_async |  4.065 us |  1.7354 us | 0.0981 us |

          Take_10byte_2sock_sync |  1.537 us |  0.9427 us | 0.0533 us |

        Take_10byte_10sock_async |  5.889 us |  8.2307 us | 0.4651 us |

        Take_10byte_30sock_async |  5.515 us |  2.4331 us | 0.1375 us |

   Take_10byte_2sock_sync_10item | 17.907 us | 28.7123 us | 1.6223 us |

 Take_10byte_10sock_async_10item | 22.929 us | 53.0855 us | 2.9994 us |

 Take_10byte_30sock_async_10item | 21.841 us |  3.7723 us | 0.2131 us |

      Take_10byte_2sock_pipeline |  4.795 us |  0.9523 us | 0.0538 us |

     Take_10byte_10sock_pipeline |  4.656 us |  0.5813 us | 0.0328 us |

     Take_10byte_30sock_pipeline |  4.735 us |  0.5510 us | 0.0311 us |

   Take_10byte_2sock_pipeline_10 | 22.294 us |  6.0993 us | 0.3446 us |

  Take_10byte_10sock_pipeline_10 | 23.485 us | 22.0893 us | 1.2481 us |

  Take_10byte_30sock_pipeline_10 | 21.890 us |  7.6632 us | 0.4330 us |

        Take_10byte_2sock_loop_2 | 29.881 us |  1.8279 us | 0.1033 us |

       Take_10byte_10sock_loop_2 | 31.114 us | 15.8645 us | 0.8964 us |

       Take_10byte_30sock_loop_2 | 33.355 us | 21.4925 us | 1.2144 us |



で、最終、Pressure検知機構を付け加えたバージョン。


                          Method |      Mean |      Error |    StdDev |

-------------------------------- |----------:|-----------:|----------:|

         Take_10byte_2sock_async |  4.040 us |  0.7995 us | 0.0452 us |

          Take_10byte_2sock_sync |  1.549 us |  0.2411 us | 0.0136 us |

        Take_10byte_10sock_async |  4.290 us |  0.9721 us | 0.0549 us |

        Take_10byte_30sock_async |  4.220 us |  1.3237 us | 0.0748 us |

   Take_10byte_2sock_sync_10item | 16.081 us | 16.7491 us | 0.9464 us |

 Take_10byte_10sock_async_10item | 20.856 us | 18.8980 us | 1.0678 us |

 Take_10byte_30sock_async_10item | 18.623 us |  6.1906 us | 0.3498 us |

      Take_10byte_2sock_pipeline |  5.197 us | 11.6224 us | 0.6567 us |

     Take_10byte_10sock_pipeline |  5.598 us |  3.1213 us | 0.1764 us |

     Take_10byte_30sock_pipeline |  5.065 us |  0.7191 us | 0.0406 us |

   Take_10byte_2sock_pipeline_10 | 22.567 us | 12.7912 us | 0.7227 us |

  Take_10byte_10sock_pipeline_10 | 25.333 us |  6.0615 us | 0.3425 us |

  Take_10byte_30sock_pipeline_10 | 23.269 us | 11.4749 us | 0.6484 us |

        Take_10byte_2sock_loop_2 | 32.199 us | 16.3175 us | 0.9220 us |

       Take_10byte_10sock_loop_2 | 35.051 us |  4.2557 us | 0.2405 us |

       Take_10byte_30sock_loop_2 | 34.979 us |  2.1891 us | 0.1237 us |



3.5用API

訳あってcore2ではなく3.5でコンパイル通って欲しいバージョンで再度ロジックのみベンチ。3.5ブランチとして吐き出そう。


                          Method |      Mean |       Error |     StdDev |

-------------------------------- |----------:|------------:|-----------:|

         Take_10byte_2sock_async |  9.446 us |  42.6027 us |  2.4071 us |

          Take_10byte_2sock_sync |  1.847 us |   0.3184 us |  0.0180 us |

        Take_10byte_10sock_async |  5.389 us |   3.2670 us |  0.1846 us |

        Take_10byte_30sock_async |  5.558 us |   1.9537 us |  0.1104 us |

   Take_10byte_2sock_sync_10item | 18.929 us |  27.2548 us |  1.5399 us |

 Take_10byte_10sock_async_10item | 22.569 us |   5.9343 us |  0.3353 us |

 Take_10byte_30sock_async_10item | 19.399 us |   3.3334 us |  0.1883 us |

      Take_10byte_2sock_pipeline |  5.485 us |   0.6061 us |  0.0342 us |

     Take_10byte_10sock_pipeline |  5.077 us |   1.6905 us |  0.0955 us |

     Take_10byte_30sock_pipeline |  6.545 us |   5.5997 us |  0.3164 us |

   Take_10byte_2sock_pipeline_10 | 31.838 us |  28.0285 us |  1.5837 us |

  Take_10byte_10sock_pipeline_10 | 28.984 us |   7.3191 us |  0.4135 us |

  Take_10byte_30sock_pipeline_10 | 26.362 us |   4.1309 us |  0.2334 us |

        Take_10byte_2sock_loop_2 | 49.594 us | 440.7760 us | 24.9047 us |

       Take_10byte_10sock_loop_2 | 43.963 us |  62.6907 us |  3.5421 us |

       Take_10byte_30sock_loop_2 | 66.129 us |  55.2169 us |  3.1199 us |


やはり目立って遅い。差はconcurrentQueueの有無なので、こう、やっぱlockより速いんだなあ。



若干のAPIパラメータを調整、デバッグ用ログの追加(オン状態)

dotnet core 2.0用のラスト。


                          Method |      Mean |      Error |    StdDev |

-------------------------------- |----------:|-----------:|----------:|

         Take_10byte_2sock_async |  4.656 us |  6.2569 us | 0.3535 us |

          Take_10byte_2sock_sync |  1.730 us |  0.9745 us | 0.0551 us |

        Take_10byte_10sock_async |  4.337 us |  0.4410 us | 0.0249 us |

        Take_10byte_30sock_async |  4.262 us |  0.7247 us | 0.0409 us |

   Take_10byte_2sock_sync_10item | 17.134 us |  8.7683 us | 0.4954 us |

 Take_10byte_10sock_async_10item | 21.383 us | 16.5207 us | 0.9335 us |

 Take_10byte_30sock_async_10item | 22.547 us |  3.6320 us | 0.2052 us |

      Take_10byte_2sock_pipeline |  6.301 us |  1.8376 us | 0.1038 us |

     Take_10byte_10sock_pipeline |  5.949 us |  2.8413 us | 0.1605 us |

     Take_10byte_30sock_pipeline |  6.673 us |  4.2911 us | 0.2425 us |

   Take_10byte_2sock_pipeline_10 | 29.744 us | 20.4818 us | 1.1573 us |

  Take_10byte_10sock_pipeline_10 | 25.569 us | 10.5866 us | 0.5982 us |

  Take_10byte_30sock_pipeline_10 | 23.797 us |  3.4032 us | 0.1923 us |

        Take_10byte_2sock_loop_2 | 35.643 us | 21.8902 us | 1.2368 us |

       Take_10byte_10sock_loop_2 | 35.144 us | 16.8500 us | 0.9521 us |

       Take_10byte_30sock_loop_2 | 35.683 us | 12.4644 us | 0.7043 us |


3.5版と比べてだいたい倍くらい高速。


wrote 2018/01/13 1:17:52

P2501アップデートポイント


概要

あのへんで使われているあれ。



主要アップデート

・Unityエディタでの動作をダイレクトに複数クライアントへオーケストレーション

・Unityエディタ経由で1台のクライアント -> 複数台のクライアントの操作を中継

・Unityエディタへとクライアントの動作記録を残せる

・Unity2017.2までのバージョンに対応

・クライアントからの詳細statsファイルの収集(Unityの仕様上、Unityエディタでしか開けない)

・全体的な高速化、軽量化



どうでもいいアプデ

・正式名称がP2501になった



Comming soon

・UI操作のキャプチャ->再現の自動化

・コンフィグ範囲をsuggestする機構

・エラー終了5秒前からの動画の投稿(PS3とかコンシューマ機のあれ

・Slack連携(エラーログの送付、他)



wrote 2018/01/09 11:38:33

実機上でテスト実行/結果収集するツールの紹介


概要

この記事はUnity Advent Calendar 2017の7日目のやつ。

https://qiita.com/advent-calendar/2017/unity


Miymamasuというテストツール作って使っているんだけどそれの紹介をする。


これ。

Miyamasu

https://github.com/sassembla/Miyamasu



実機でしか動作しないものを自動で手軽に適当に動かして、本当に動作するのか試したい、、試したくない、、?

課金機能、

E2E的な処理、

処理速度、

あの画面が表示されるまでにどんな絵がでるの? みたいな。


そんなあれこれを、実機上で動かして収集する話。



Miyamasuでできること一覧

テスト書く -> Editorで実行 -> レポートをSlackに送信

-> Playerで実行(Editor上) -> レポートをSlackに送信

-> Playerで実行(実機) -> レポートをSlackに送信


このオール ハイル テスト感。



サンプルシナリオ

あるシーンをAdditiveで開いて、その上で適当な関数を実行するテストを用意してみようかと。

1.BaseSceneでアプリを起動、

2.TestTargetSceneをロードしてロード後のスクリプトにアクセスし、

3.プロパティが正しいパラメータを返すかをチェックする。

4.その時のスクショを撮る


0.インストール

Miyamasuのunitypackageをここからダウンロードしてunitypackageを実行、とりあえず全部入れる。

Unity -> Window -> Test Runner を押して、テストウィンドウを開く。


ウィンドウが開いたらPlayModeボタンを押す。

スクリーンショット 2017-12-06 17.40.14.png

Enable playmode tests ボタンを押す、するとこんなのが出るので、

スクリーンショット 2017-12-06 17.40.19.png

OKを押してUnityEditorを終了 -> もう一度起動。手で。そう。手で。


もう一度 Test Runner を開くと、

スクリーンショット 2017-12-06 17.40.42.png

こんな感じになってればOK。もうボタン押さないでいい。


このように、プロジェクトごとに、初回だけEditorの再起動が必要になる。


1.まずテストを書く

testのコードを、適当にAssetsフォルダ以下に書く。

こんな感じ。


Assets/Tests.cs

using System.Collections;

using System.Collections.Generic;

using Miyamasu;

using UnityEngine;

using UnityEngine.SceneManagement;


public class Tests : MiyamasuTestRunner {


    [MSetup] public IEnumerator Setup () {

        var loadAdditionalScene = SceneManager.LoadSceneAsync("TestTargetScene", LoadSceneMode.Additive);

        while (!loadAdditionalScene.isDone) {

            yield return null;

        }

    }

    [MTeardown] public IEnumerator Teardown () {

        var unloadAdditionalScene = SceneManager.UnloadSceneAsync("TestTargetScene");

        while (!unloadAdditionalScene.isDone) {

            yield return null;

        }

    }


    [MTest] public IEnumerator CheckRunning () {

        var instance = GameObject.FindObjectOfType<TestTargetScript>();


        NotNull(instance);

        IsTrue(instance.Running);


        yield break;

    }

}


MSetupアトリビュートが付いているメソッドはテスト前に、MTeardownアトリビュートが付いているメソッドはテスト後に実行される。

それぞれTestTargetSceneをロードしたりアンロードしたりしてる。


MTestアトリビュートがついてるメソッドは、Setup、Teardownの間に実行される、テストのメイン部分。

この関数名がそのままテストケースの名前になる。


ここでは、TestTargetScriptのインスタンスを探し、nullでないこと、instane.Runningがtrueを返すことを期待している。

IEnumeratorを返す関数しかテストケースにできないのだけど、今回のテストでは非同期さをテストの対象にしてないので、

yield breakして終わり。



2.Editorでコンパイルが走ると、書いたテストの名称が実行可能なテスト一覧に出る

こんな感じ。

スクリーンショット 2017-12-06 18.10.38.png

で、CheckRunningをダブルクリックで実行! なんかゴウンゴウン動いて、、

無事Passした?


スクリーンショット 2017-12-06 18.11.21.png

やったぜ。


この機構はUnityの5.6以降だと動かせる、UnityTestの機構を使っている。

というかMiyamasuがUnityTestのコードを自動生成しているので、まあ、なんだ、

UnityTestでできることはMiyamasuでも全てできる。


で、Miyamasuを使うとさらに便利なことができる。

例えば「Editorに接続されていない端末でもテストを実行する」「その結果を収集する」とか。

以降で紹介する。



3.Playerでもテストを実行してみる

ここで、思いついたようにPlayを押してみると、先ほどと同じテストがPlayerでも実行される。


スクリーンショット 2017-12-06 18.11.42.png


Playerで実行した場合、GUIがなんか出る。まだ適当なのであまりいいUIではない。


ちなみに全件自動的に実行される。


この状態で実機ビルドを行うと? 

そう、実機でも同じテストが自動的に実行される。結果もGUIから観れる。

今回は割愛するけど、Failした場合はエラーログも出て、端末へとコピーしたりできる。


4.ログ

Editor上で実行した場合は、ログがプロジェクトのフォルダの miyamasu.log ってファイルに吐かれるので、

まだJenkinsとか使ってる人とかはこの辺を使うといいと思う。


あとローカルでtail -f したりすると観やすい。内容はこんな感じ。

スクリーンショット 2017-12-06 18.12.47.png


当然実機上ではこのログは吐かれない。CloudBuildでもログを得るのは面倒臭い。


ではどうする? 

よろしい、Slack連携だ。 (Slack!! Slack!!



5.Slackの設定をしよう

この段階では、Slackへとテストレポートを送る機構が働いていない。


設定は、Unity -> Window -> Miyamasu Test Runner -> Open Settings からできる。

スクリーンショット 2017-12-06 21.28.13.png


slackTokenslackChannelName をセットすると、テストの成否に関わるログが自動的にSlackのそのチャンネルへと転送されるようになる。

これは当然実機で実行した場合もそんな感じなので、こう、なんだ、楽。

slack上ではこんな感じに表示される。

スクリーンショット 2017-12-06 18.55.29.png


デバイス名は自動的に取得される。やったぜ。



5.動作時のスクリーンショットを撮ってSlackに送る

testの途中で、今どんな状況なの?ってのをスクショしたい時あると思うんだけど、

そのへんはコードを足すとできる。


Assets/Tests.cs(抜粋)

    [MTest] public IEnumerator CheckRunning () {

        var instance = GameObject.FindObjectOfType<TestTargetScript>();


        NotNull(instance);

        IsTrue(instance.Running);


        yield return SendScreenshotToSlack("TestTatgetScene”);// これで、この瞬間の画面のスクショを送り出せる。

    }



Slack上にこんな感じでスクショが出る。もちろんMiyamasuのインターフェースは映らない。

スクリーンショット 2017-12-06 20.10.06.png



Sampleリポジトリ

このサンプルシナリオを実装したリポジトリを用意した。


Miyamasu2Slack

https://github.com/sassembla/Miyamasu2Slack



このプロジェクトでは、特定のシーンを読みだしてその時のスクショがどう、みたいなのを実機上でも実行できる。

当然ながらslackTokenとかは入ってないのでこう、なんだ、あれだ、頑張って。


参考 slack設定あれこれ

http://sassembla.github.io/Public/2017:12:06%2013-21-52/2017:12:06%2013-21-52.html


wrote 2017/12/07 00:00:00

5分でわかるSlack連携


概要

MiyamasuからSlackに対してアレコレする機運なので最小構成でslackの設定をする。


実装していく

投稿はhttpsとかでできるので、Miyamasuからデータを送り出せるようにする。


・webhookを有効にする

・tokenを取得する

という手順をこなす。

tokenはここから取れる。

https://api.slack.com/apps/ZZZZZZZ/install-on-team?(ZZZZZZZにはworkspace idとかが入る)

で、scr.pngっていうファイルを用意して、slackの特定のチャンネルへと送付しようとする。


curl -F file=@scr.png -F channels=#miyamasu -F token=xoxp-XXXX https://slack.com/api/files.upload


こんな感じのやつを実行すると、次のエラーが出る。

{"ok":false,"error":"missing_scope","needed":"files:write:user","provided":"identify,incoming-webhook"}


ふむふむ、scopeが見つからんと。

https://api.slack.com/apps/ZZZZZZZ/oauth?


このへんで調整。

スクリーンショット 2017-12-01 13.38.18.png


これかな。追加して保存。


あわせて、miyamasuというチャンネルを作っておいた。




この状態で同じコマンドを実行すると、動いた。いい感じ。



で、メッセージを送る方も、tokenを使ったものがあるのでは的な感じ。


curl -X POST -H 'Authorization: Bearer xoxp-XXXX' -H 'Content-type: application/json' --data '{"channel":"miyamasu","text":"I hope"}' https://slack.com/api/chat.postMessage


テキストを送ろうとすると、また別のエラーが出る。こんな感じ。

{"ok":false,"error":"missing_scope","needed":"chat:write:user","provided":"identify,incoming-webhook,files:write:user","warning":"missing_charset","response_metadata":{"warnings":["missing_charset"]}}


chat:write:user というパーミッションを足して再度実行すると動く。いい感じ。

これでwebhook消していいのではという感じ。


スクリーンショット 2017-12-01 13.54.13.png


と思ったら、この設定はベーシックなので消せないそうだ。そういう感じなのか。



文言を送る

curlだとこんな感じ。

curl -X POST -H 'Authorization: Bearer xoxp-XXXX' -H 'Content-type: application/json' --data '{"channel":"miyamasu","text":"I hope"}' https://slack.com/api/chat.postMessage



画像を送る

curlだとこんな感じ。

curl -F file=@scr.png -F channels=#miyamasu -F token=xoxp-XXXX https://slack.com/api/files.upload


画像を送る場合、Screenshotをとってそれをバイト列として取得して送り出す、みたいなのを、マルチパートポストで頑張る必要がある。

人生で一度だけ頑張ればなんとかなる。



wrote 2017/12/06 13:21:52

.NET Coreでnugetを簡単につかう


概要

詳しくないので簡単に。


コマンドラインから。


dotnet add package


ね、簡単でしょう?



wrote 2017/12/03 12:53:04

NATについて学んでみる + nginx-lua改造で簡単にNAT越えやってみる


概要

やってみたくなった。

改造、という言葉がある時点で泥沼になるのは予想できるよね?



NAT

いろいろ。ここの解説がわかりやすかった。

https://plaza.rakuten.co.jp/hisuirai/diary/201211080000/

http://www.think-like-a-computer.com/2011/09/16/types-of-nat/


Cone

full cone NAT

address restricted cone NAT

port restricted cone NAT


Symmetric

sequential port symmetric NAT

・random port symmetric NAT

要件

nginx luaを介して情報交換し、クライアント間でP2Pできるようにする。ようは、nginx luaでシグナリングを行う。



かなったこと

クライアントA,Bに対して、A,Bがサーバに送付したudpパケットを元に、nginx streamを介してシグナリングを行い、A-B間でP2Pができるようにする。

TURN機構は含まないため、symmetric natは突破というか、解決しない。



実証実験環境

udpを受け付けるサーバを立てて、そこにクライアントからudpを送る -> 

サーバ側から状態を観測、変換済み/到達可能なip:portをクライアントに返す -> 

クライアントはws接続時にそのパラメータを送ってきて、ws接続寿命の間はudpでのデータ送信ができる、という状態になる

面白い話:モバイルルータとNAT越え

http://custardfilleddonut.blog.fc2.com/blog-entry-19.html


mobileRouterによっては、公式にSymmetricNATを使っていて、NAT越えしづらいのが把握できる、という感じの話がある。

プレイヤー間p2pなどで、サーバ以外の2者をつなぐのがしんどい。turn必須になっちゃう。



現在までの理解:

・やりたいことは、サーバからudpを使ったpushをクライアントへと送ること。

・クライアント側はNATの向こう側にいることが多いので、NATを越えられる状態が必要になる。

・サーバにむけてudpを打てれば、サーバからudpを送り返すことはできるようになる(情報が揃う

full corn -> そのまま送り返せばOK(ごく稀に存在。

address restricted -> 送信先からの返信ならばそのままでOK、そうでない場合、双方向にパケットを打って経路を構築する必要がある。

port restricted -> 受信側 = サーバでポートを観測できてればOK



想定できる安価なケース

1.nginxでudp通信を受ける

2.ip、portをユーザー単位で保存する

3.なんらかの方法でnginx_luaでのws設立タイミングでその情報に触れる(ユーザー単位での情報のすくい上げを行う

4.nginx_luaからudpを発信する際にその情報を使う(接続の再セットを行う際は、ws経由でサーバに送って云々になる。


1~3で、同じnginxが使われれば最高という感じ。

udpサーバは、ユーザーid+tokenのような情報を受け取って、ipとportを保存する。

これだけでOKなはず。


full: クライアントからのudp送付元がそのままudpを返せるのでOK

address restricted: クライアントからのudp送付元がそのままudpを返せるのでOK

port restricted cone NAT: 


もっと安価なケース

nginx stream moduleを使う。

1.3以降だと入れられそうで、あとはなんというか、Dockerで動かしてlistenができればいいのか。

-> 対応ポートに/udpつけたらudpに対応した。これで、Dockerでnginx stream udpの受付ができた。

で、

アプリケーションを動かして、udpを受け取り、そのaddrとportを覚えておく必要がある。

まずはnginx-luaのstreamモジュールでやってみるか、、あれでudpを受け取って辞書が使えればベスト。うーん、この構造はダメっぽいかな。


・そもそもwsと共存できてる?

・udpでのデータを受け取って、nginx_luaから触れるようにするにはどうするか:idをパラメータにしてしまうか。それともudpでレスポンスを返すようにするか。

レスポンスそのまま返せると思うんだよな。

-> 返せた。で、LAN環境だと返答も受け取ることができた。

で、あとは、AWSにのっけてテスト。


-> 今回はstreamを使ってudpのserver/senderを立ち上げておき、そこを経由してデータを流すことで実現した。



特定のポートからudpを射出する装置 みたいなのがあればいいのか よさそう。それが特定のポートをlistenしてるソケットである必要性がある?

ありそう。


nginx unit goでそのまま起動できるudp 反射機を用意して、そこにip  + ポートで送出させればよさそう。

その機構とnginx luaとのコミュニケーションはどうやるのがいいんだろう。udp?まあそれでも良さそう。


こうすると、udpポートを1つしか消費せず、データを流せる。


事前にws -> キーを返す -> キーをudpサーバに送る -> udpサーバでip:port:キーを保持、

nginx luaからudpをキーで送出 -> リフレクタがキーからデータをip:portへと送付


うーーん大変そう。でもudpだから平気かな。どうせ送り出すのは変わらないわけで。udpで送り出せばいいか。

この部分を組むか。それでudp沼はおしまい。

udp multiplexを勉強してみよう。


-> 結果的に、nginx luaのudp送出でポートを指定できればそれで良さそう。



nginx luaを改造するためにコードを読む

このprでtcp bindが提供されてるんだけど、こんな感じでudpのポートを指定するやつを書ければいいんだと思う。

https://github.com/openresty/lua-nginx-module/pull/712/files

・定義

・cの関数を書く

あたりが必要。

nginx luaを書き換えつつコンパイルすればいいのだろうと思って動かしてみる。


nginx luaのcosocketを書き換えてみる。

-> socketaddrっていうstructがあって、そいつが宛先の情報を持っているんだけど、送信時に送信ポートを指定する手段がなさそう。

これは何というか、ipv4とか6とは切り離されたパラメータだからっぽい。


luaのudpソケットについて調べる。


これsendとreceiveが一致してるような感じなんだよな。というか送り元はポート指定できない的な。

送り先のポートは指定できるんだけど、送り元のポート指定ができない。


これが指定できれば苦労しないんだよな多分。


-> 送り元のポート指定は無理っぽい。sockaddr structになってしまっていて、多分もともとできない。

で、残った手としては、通信を受けるのに使っているポートを割り出して、そのパラメータをクライアントへと伝え、クライアントから通信させる。

残念な点としては、udpの受け口がとても広範囲に必要なこと。ただしポートを消費しない。経路確立してしまえばそのまま送り出せる。


送り元のポートは、connectionそれ自体のポートを使用している。こうすることで、ポート消費を抑えている。



おまけ


ネットワーク帯域を計測する

https://qiita.com/takish/items/3a9ea74cfec4683ddf56



Lua udp sock

https://github.com/openresty/lua-nginx-module/blob/master/t/087-udp-socket.t



クラウドフレアの記事 大量通信を低レイテンシでみたいな話。

https://blog.cloudflare.com/how-to-achieve-low-latency/



ファイルディスクリプタについて

プロセスや実行ファイルにとって外部の資源にアクセスしたりアクセスされたりする際に使用される抽象的なインターフェース

-> nginxだと、一つのワーカーごとに開けるコネクションの数になっていたはず。workerに対して保持できるfdの数を増やして対応していた。


Pacingの話

http://www.aist.go.jp/aist_j/press_release/pr2005/pr20050606/pr20050606.html



wrote 2017/11/13 16:36:56

fbxImportの中心がずれる


概要

ZBrushで特定のモデルのインポート時に中心がずれる。fbxデータ的には中心ちゃんとしてそうなんだけど。

で、調べてみてるところ。



試す

https://togetter.com/li/601793


この辺かなあ。

なんか対処するなら、その辺もimport -> 左右対称パーツの左右対称化 -> ZRemesh時に自動化したいところ。


wrote 2017/10/31 16:59:01

Mediumで造形する時の手順メモ


概要

かなりノウハウが形になってきたので覚え書き。



1.絵を描く

あったほうが結果的に早い。



2.絵を見ながら頭身をざっくり作る。

sassembla_2017-10-19_08-21-57.png



3.外形を作って、切断面になりそうなところに来たら切る

カットツール使って切る。


その際、左右対称であってほしいけど左右に分割されている = 左右が切断されているパーツとかは、

そのままカットすると左、右の2つのレイヤーに分かれてしまうので、

・カットする前にClayで左右をつなぐパーツを作る

・切断したい面をカットする

・つないでいたパーツを削り切る


とかすると、大変スマートに切断後も1レイヤーで居てくれる。

sassembla_2017-10-22_22-27-42.png



4.細かい部分は、色を塗りながらMoveツールで変形すると捗る

テクスチャのもとになるカラーなんだけど、Mediumだと「塗りながらMoveツールでいじる」とかができるので、

・目のサイズを雑に描いて決める

・そのサイズに合わせて頭パーツの凹凸を調整する

ということがシームレスにできる。


あと完成時のイメージとは関係ないんだけどメタリックパーツは燃える。

sassembla_2017-10-30_09-05-45.png




5.Exportする

まだ試行錯誤中なんだけど、思っていたよりもZBrush/ZRemesherが強力なので、その辺に頼る形で

高ポリゴンな状態でexportしても問題ないかもしれない。


テクスチャをいい感じの密度で出力するのはまだ実験中。

wrote 2017/10/31 1:16:11

ZBrushでfbxImportする時の引っ掛かりごと


概要

きっとこの世のどこかに書いてあると思うんだけど、備忘録までに。

Oculus Mediumとかで出力したfbxが、fbxViewerとかだと問題なく表示されるんだけど、

ZBrushのimporterでfbxをimportすると不具合が出る。



import方法

ZPlugin > FBXImportExport > Import .. 

ふつう。


fbx上で存在していたレイヤーが消える?

毎回特定のレイヤーが消えることがあって、なんかの条件がありそうな。

-> 名前が同じパーツをfbxでexportすると、ZBrushはどちらか片方しか読み込めない

ということで、fbx exportをする側で、ユニークなレイヤー名をつけよう。







wrote 2017/10/26 8:31:55

自作Preloaderの素晴らしい挙動


概要

作った時は全くそんなこと考えてなかったと思うんだけど結果的に素晴らしくなっていた。

覚え書きまでに。


Autoya Preloader

これ。

AssetBundlePreloader.cs

https://github.com/sassembla/Autoya/blob/master/Assets/Autoya/AssetBundle/AssetBundlePreloader.cs


実際にAssetを使用する前に、AssetBundle(AB)を名称指定でDLしておく、という機構なんだけど、

AB同士の依存解決についていい塩梅に怠惰だった。


そのため、最小のDL範囲で動く、ということを実現していたので内容について書いておく。



依存解決と展開

ABを作成する際に、依存関係は勝手に作成される。

AssetGraphとか使うと作成自体は楽。


で、「とりあえず該当するABだけを、使用可能な状態で保持する」というのを実現するにはどうすればいいか。

すごく単純で、そいつの依存だけをとりあえず解決すればいい。


もし次のような依存があるABがある場合、


a -> b -> c


aをDLする際、a, bまでは取得してしまっていい。

で、実際にaを使う際には、aとbだけがあれば用は足りる。


では、bを使おうとすると?

bのロード時にcに依存しているのが解決されるので、問題ない、という。


良かった良かった。


というわけで、たった1段だけの依存解決でPreloadの用は足りるんだなあというのを

いつかの自分の実装から把握するなどした。




wrote 2017/10/23 19:17:18

Oculus Medium v1.3までにできるようになったこと


概要

Medium用のWindowsパポコン壊れたの直してる間にものすごく機能が増えていた。

まとめる。



以前の記事からだと次のような追加点がある。

・reference image からのスポイトカラー取得

・reference modelでの高解像度モデルの読み込み

・Moveツールの追加

・拡大縮小、移動、回転操作の追加



reference image からのスポイトカラー取得

参考用に操作空間内に画像を貼ることができたんだけど、そこからカラーツールでスポイトを使って色を取得できるようになった。

素晴らしい。



reference modelでの高解像度モデルの読み込み

importとは少しちがうのだけれど、reference imageと同じように、モデル(obj or fbx)を読みこんで、

画面内に自由に置くことができるようになった。

解像度とかはそのままオリジナルのものが出せる。Mediumで生成 -> fbx化した10万ポリゴンとかも綺麗に出た。

この延長線上でimportができると嬉しいなあ。



Moveツールの追加

特定の範囲を掴んで、回転を加えたりしながら移動させることができるようになった。

例えば髪のモデリングをしたり、ちょっとした手足の回転、位置調整とかを行う際に

本当に便利。


当社比100倍の効率。

素晴らしい。



拡大縮小、移動、回転操作の追加

各レイヤーごとにできるようになった。

数値系の入力での位置セットも可能になったので、exportとかの時に嬉しい予感がする。



wrote 2017/10/23 14:48:45

AppManifestモジュールについて


概要

アプリケーションの設定ファイルを読み書きする機構。

Autoyaのモジュールの一つ。

https://github.com/sassembla/Autoya/tree/master/Assets/Autoya/Manifest



重要な制約として、string以外の型を保持できないようにしてある。


サンプル

https://github.com/sassembla/Autoya/blob/master/Assets/AutoyaSample/10_AppManifest/AppManifest.unity


おまけで、UnityCloudBuild上でビルドした場合、

CloudBuildのパラメータも取り込んだ情報を取得できるようにしてある。(もしかしたら動いてないかも)


あとshellからビルドメッセージを入れたりできる。



用途

アプリケーションの運用に際して、事前に定義したパラメータを管理するのに特化している。

アプリケーションの運用以外に関するパラメータを管理するために使うのは得策では無い。



アプリケーションで保持、管理したいパラメータ

1.ビルド時に決定されるreadonlyなパラメータ

2.ビルド時に初期値が決定され、更新されるパラメータ

3.動作時に新規に追加、上書きされていくパラメータ


だいたいこの三つがあると思う。

AppManifest機構では、1と2を扱う。3はInAppDBなどで扱う。


1.ビルド時に決定されるreadonlyなパラメータ

アプリケーションのバージョン、ビルド時の情報など、

外部から参照して使うのみのパラメータ。


よくタイトル画面に表示したりする。

パラメータ名から値までが完全に決定された状態。



2.ビルド時に初期値として決定され、それ以降更新されるパラメータ

事前にキーが決まっているパラメータ。

外部から参照して使うほか、更新が発生したりする。


事前にキーが決まっており、深度も決定されているが、変更が発生することがあるのが1との違い。


予期されている範囲での変動を保持する。


3.動作時に新規に追加、上書きされていくパラメータ

1,2以外のクライアント側でのpersistantな要素。

要はDB。

キーが増えたり、深度が変わったりする。初期値もあったりなかったり。

真面目な運用を考えるとまあ可変キー、可変深度になると思う。

型も多岐にわたる。



AppManifest

次のような階層構造になっている


AppManifestStore

BuildManifest

ビルド時に決定されるパラメータ集

RuntimeManifest

ビルド時に初期値として決定され、それ以降更新されるパラメータ集

で、


取り出しはAppManifestStore経由で、辞書形式で取得できるようになっている。

RuntimeManifestパラメータに関しては、取り出し -> 変更 -> 上書き、ができる。


read/writeに関する機構は外部から渡すことができる(暗号化/復号化フック書ける)

BuildManifest、RuntimeManifestに使用するデータ型は外部から渡す。



それぞれの保存形式


BuildManifest

実行時書き換え機構を持たないため、まんまResourcesフォルダ以下にjson形式で保存されている。

RuntimeManifest

実行時書き換え機構を持つため、アプリケーションの実行環境に保存される。

保存メソッドは外部から与えることができる。


両方とも、生成元となる型を与えて生成するデータの形状を規定する。

生成元の型情報に初期値をセットすることができる。


重要な制約として、string以外の型を保持できない。



Autoyaでの使用例

Autoyaでは、2つのバージョン値を使ってユーザーの手元のゲームを管理できるようになっている。


appVersion

アプリケーションのバージョン


resVersion

リソースのバージョン


appVersion

appVersionはアプリケーションの実行バイナリの更新でのみ変動するため、

BuildManifestのパタメータとして保持している。

認証がある通信に際して、サーバ側にクライアントアプリのバージョンを通知するために使っている。

サーバはこの通知をもとに、「君のアプリは古い。こっちを使いなさい」とか返答を寄越してくる。



resVersion

resVersionはアプリケーションが現在保持しているDL可能リソース全体のバージョンを表象している。

これはアプリの運用中に変化していく(だいたいincrementされる)ため、

RuntimeManifestのパラメータとして保持している。


認証がある通信に際して、サーバ側にクライアントのDL済みのリソースバージョンを通知するために使っている。

サーバはこの通知をもとに、「君のアプリのリソース情報は古い。こっちを使いなさい」とか返答を寄越してくる。



wrote 2017/10/12 4:47:46

AutoyaでのappVersion/resVersionの変化と挙動について


概要

Autoyaでは、主に2つのバージョン値を使ってユーザーの手元のゲームを管理できるようになっている。


特にresVersionがこれ超かっこいい機構なので解説する。

まだ上書きの予約の実装みたいなのが終わってないんだけど。



よくあるアプリケーションの運用概念

・最新版を配布しだしたのでユーザーに最新Appを取得してほしい

・DLリソースを追加したのでDLのための事前情報をAppに与えて最新リソースをDLさせたい

など。このへんはまあ最低限。



最新版を配布しだしたのでユーザーに最新Appを取得してほしい

Autoyaでは、appVersionというパラメータを使ってこれを実現できる。


・Assets/Autoya/Settings/AutoyaBuildManifestObject.csのappVerionにアプリケーションバージョン値を入れる

・AutoyaのHttpモジュールを経由した通信では、requestHeaderにappversion=“1.0.0”のようなパラメータが入る。

・サーバ側でその値を確認し、アップデートしてほしいバージョンだった場合、responseHeaderにappversion=“1.0.1”などと返すと、

クライアント側はその要求を受け、OverridePoints.cs/OnNewAppRequested メソッドが着火される。


このメソッド内で「新しいAppがあるのでDLしてね!」って書いたりするといいと思う。



要は、次の3ポイントでアプリケーション更新が実装できる。


1. AutoyaBuildManifestObject.csにいい感じのappVersionを書く

2.サーバ側から適当なタイミングでresponseHeaderにappversion=”X.Y.Z”とかを返す

3. OverridePoints.cs/OnNewAppRequested メソッドにアプリケーション更新UIを出したり、ストアに遷移するコードを書く



DLリソースを追加したのでDLのための事前情報をAppに与えて最新リソースをDLさせたい

Autoyaでは、resVersionというパラメータとAssetBundle関連の機構でこれらを実現している。


・Assets/Autoya/Settings/AutoyaRuntimeManifestObject.csのresVerionにリソースバージョン値を入れる

・AutoyaのHttpモジュールを経由した通信では、requestHeaderにresversion=“1.0.0”のようなパラメータが入る。

・サーバ側でその値を確認し、アップデートしてほしいバージョンだった場合、responseHeaderにresversion=“1.0.1”などと返すと、 クライアント側はその要求を受け、OverridePoints.cs/OnRequestNewAssetBundleList メソッドが着火される。

このメソッドには、今すぐ最新リソースリストをDLするか否か、YesかNoで返すことができる。

Yesと答えるとバックグラウンドで新しいリソースリストのDLが開始される。

Noと答えるとリクエストは発生しない。


バトル中など、リストが更新されても特に影響のない、横槍を受けたくない箇所ではNoを返すといいと思う。

ちなみにYesを返してもNoを返してもゲーム側に何かデータ処理を要求することはない。

使用しているAssetBundleにも影響はない。


・Yesと答えて新しいリソースリストのDLが完了すると、OverridePoints.cs /ShouldUpdateToNewAssetBundleList メソッドが着火される。

このメソッドには、DLが完了したリソースリストを今すぐ適応するか否か、true/falseで返すことができる。


trueを返すと、リソースリストが更新される。現在使っているAssetは次回ロード時に自動的に最新のものを取得してくるようになる。

falseを返すと、リストの更新は延期される。新リストのデータはメモリ上にキャッシュされているため、次回以降のDLは発生しない。


ちなみにtrueを返してもfalseを返してもゲーム側に何かデータ処理を要求することはない。

使用しているAssetBundleにも影響はない。


・リスト更新後、AutoyaのHttpモジュールを経由した通信では、requestHeaderにresversion=“1.0.1”など、更新後のパラメータが入る。

・これ以降、ゲーム中でロードされる素材が自動的に最新のリストに記載されているものになる。

端末内に最新データが存在しない場合、使用するタイミングでダウンロードが発生するので、

そういった形式になるのが困る場合はPrelaod機構を使うことをお勧めする。

(preload機構は事前DLさせるリソースをサーバ側で変更できる。)



要は、次の4ポイントでアプリケーション更新が実装できる。


1.Assets/Autoya/Settings/AutoyaRuntimeManifestObject.csのresVerionにリソースバージョン値を入れる

2.サーバから適当なタイミングでresponseHeaderにresversion=“X.Y.Z”とかを返す

3.OverridePoints.cs/OnRequestNewAssetBundleList メソッドでYesかNoを返す

4.OverridePoints.cs /ShouldUpdateToNewAssetBundleList メソッドでtrueかfalseを返す


wrote 2017/10/12 4:46:48

Gitpitchが便利だったのでプレビュー用の機構作った(追記あり)


概要

これ

GITPITCH

https://github.com/gitpitch/gitpitch


・Github上のPITCME.mdという名前のmdファイルをスライドに変換して見せてくれるサービス

・文字フォーマットとかのデフォルトが見やすめ

・画像とかも置ける


欠点がないわけではなくて、特に簡単にプレビューできないというのが自分の場合特に辛かったんで、こう、解決しようかなと。


プレビューしたい、、プレビューしたくない?

ユーザーのブラウザ -> gitpitch -> github/repository/branch/PITCHME.md というルートでスライドの元となるmdを取得する感じになってるんで、

ようはgithubにpushしないとスライドが見れないっていうのがあって。


branch切ってそっちにアップして完成したらmasterに合流~みたいなの書いてあるっぽいんだけどそうじゃねーんだよ、

根本的にcommit pushせんでもプレビューしたいんだよ。



issue closed

preview関連のissue見てたら解決したようなそぶりになってるんだけど実質面倒臭くて解決してねーじゃねーか、

みたいなのを見つけたので、解決策として一個なんか作った。


offlineモードの延長線上でプレビューと言い張る

これが一番現実解な気がする。楽だし。

現状PITCHMEにはオフラインモードがある。

スクリーンショット 2017-10-03 16.01.18.png

このオレンジに光ってるやつを押すと、プレゼンアセット全体がDLできる。

DLできて、index.htmlも入ってて、

ああーこれひらけばいいんじゃねってなるんだけど、そのままローカルで開くとhttpサーバでないと解決できないCORS関連の動作があるらしく、

ロードに失敗する。


この動作は意図してないものなんじゃねーかな~と思いつつ、じゃあhttpサーバに乗っけたら動くのかよ、っていうと問題なく動いた。


で、このDLできたアセット全体は、こんな感じのフォルダになってて、PITCHME.mdも入ってる。スクリーンショット 2017-10-03 16.04.44.png

なんだ入ってるんじゃん、という感じで、この.mdを編集するとちゃんとコンテンツも変化する。

やったねプレビューできるよ。HTTPサーバに置けばね。



で、どうやるのが一番楽か

いろいろ考えたんだけどなんかもうDockerでnginx立ててそっから見れる場所にgitpitchのファイルを置けばいいと思うんだよね。


というわけでこれ。


GitpitchPreview

https://github.com/sassembla/gitpitchpreview


使い方はREADMEを見てもらうとして。



これでローカルで編集して気が済んだらcommit pushで運用できるぞ=~~



以下追記


今後の課題

・nginxのキャッシュ設定いじってないので、mdやassets/以下の画像を弄っても変わらない時がある。

https://github.com/sassembla/gitpitchpreview/issues/2

・offline出力をする際にmdの中の画像が強制的にassets/以下にまとめられる。このほかにもオリジナルのmdとは変更点が多い。

1.画像がassets/以下にまとめられる

2.md内の画像リンクもassets/以下を指すようになる

3.@[1] とかの記法は<span class="code-presenting-annotation fragment current-only" ,, みたいなタグに展開された状態で来る


という感じで、offlineで持ってきたmdをそのまま使うのは厳しい。


が、試しにオリジナルのmd(@[1]とかの記法を使ってるやつ)を置いてみたところ、変換されない状態で表示されてさらに厳しいことになったので、

うーーーんんん、、、、


Offlineから取得したmdをいじる場合、しんどい部分がある

という感じに着地してしまった。うーん、、、


余談、どうできると綺麗か

結局gitpitchは、


ブラウザからgitpitchサーバを介してgithub/user/repoにアクセスする際、


1.pitchme.mdを変換したものを、

2.jsとかで動作可能にしたものとして、

3.ブラウザに表示する、


という経路を経ている。


で、


offline出力で取得できるものはこのフローの2から先を渡してくれるだけなので、

1を2に変換する工程はgitpitchのサーバに含まれてしまっていて、まあ再現できなそう(さらに不可逆なのがキツい)。


うーーーん。かなしみだ。


というわけで、「文言の変更に関しては」プレビューが完璧にできる。という程度なことがわかってしまった。


だれか改善して。



wrote 2017/10/03 14:25:04

Crowiをdeploy to Herokuでデプロイして画像OKにする


概要

Crowiをなるべく怠惰にクローズドで使いたかったのでdeploy to herokuボタンをポチッと押した。

大変便利。


で、その後、設定を変えないといけないのでちょっと触ってるみたいな話。


少量だけど画像もアップしたりしたい、、というやつ。

でハマった。



デフォルト

デフォルトではAWSのS3とかに画像をアップできるように設定されている。

AWS側のパラメータセットがなければ何も起きない(画像をアップできないようになっている)


で、これは.envファイルをアップしたりすれば解決できるんだな~という判断をして、

herokuに上がっているものを編集する旅に出ることになった。



設定を変えたいんだ

具体的にはheroku上に.envファイルを足したり編集したりして云々がしたい。


herokuはgithubからのデプロイ以外にもheroku CLIからのpushもできて素敵、みたいな感じなんだけど、

deploy to herokuボタン一発でアップされたアプリケーションは、なんというか特殊っぽくて、

デプロイ元のgitリポジトリを持たないみたいだ。


heroku gitで取得しても空のフォルダが出来上がる。


で、herokuからソースコードを取得して設定ファイルを追加、その上で再度アップして云々ってのをやる必要がある。



バックアップ

既存のコードを取得するための処理が行えた。slug。

https://kb.heroku.com/how-can-i-download-my-code-from-heroku


slugプラグイン入れてheroku slugs:download -a APP_NAME でOK。

実行するとアプリケーションのファイルがまるっと手に入る。

(もしかしたらここが不十分とかそういうのかな、、あとで問題が出る。)



このときの現状

・手元にはherokuにアップされていたファイルがすべて?ある

・これらをherokuへとアップし直すことで、デプロイとか更新ができる。はず。

スクリーンショット 2017-10-04 14.43.52.png


node_modulesはまあ現地で展開してくれそうなのでgitには含まないようにして、herokuへとpush。



で、herokuへとpushしたあたりで問題が

deploy時のpostinstall処理でこんな感じのエラーが出る。


remote:        > crowi@1.6.2 postinstall /tmp/build_d989cb6fdb4acc6a79775c1d6949d915

remote:        > gulp

remote:        

remote:        [05:14:06] Using gulpfile /tmp/build_d989cb6fdb4acc6a79775c1d6949d915/gulpfile.js

remote:        [05:14:06] Starting 'css:sass'...

remote:        [05:14:06] Starting 'js:del'...

remote:        [05:14:06] Finished 'js:del' after 25 ms

remote:        [05:14:06] Starting 'js:concat'...

remote:        [05:14:06] Finished 'js:concat' after 45 ms

remote:        [05:14:06] Starting 'webpack'...

remote:        [05:14:08] Finished 'css:sass' after 1.82 s

remote:        [05:14:08] Starting 'css:concat'...

remote:        [05:14:09] Finished 'css:concat' after 1.33 s

remote:        [05:14:09] Starting 'css:min'...

remote:        [05:14:10] Finished 'css:min' after 982 ms

remote:        

remote:        internal/streams/legacy.js:59

remote:        throw er; // Unhandled stream error in pipe.

remote:        ^

remote:        Error: ./resource/js/app.js

remote:        Module build failed: SyntaxError: Unexpected token (45:17)

remote:        

remote:        43 | const componentMappings = {

remote:        44 |   // 'search-top': <HeaderSearchBox crowi={crowi} />,

remote:        > 45 |   'search-page': <SearchPage crowi={crowi} />,

remote:        |                  ^

remote:        46 |   'page-list-search': <PageListSearch crowi={crowi} />,

remote:        47 |   'page-attachment': <PageAttachment pageId={pageId} pageContent={pageContent} crowi={crowi} />,

remote:        48 |

remote:        

remote:        BabelLoaderError: SyntaxError: Unexpected token (45:17)

remote:        

remote:        43 | const componentMappings = {

remote:        44 |   // 'search-top': <HeaderSearchBox crowi={crowi} />,

remote:        > 45 |   'search-page': <SearchPage crowi={crowi} />,

remote:        |                  ^

remote:        46 |   'page-list-search': <PageListSearch crowi={crowi} />,

remote:        47 |   'page-attachment': <PageAttachment pageId={pageId} pageContent={pageContent} crowi={crowi} />,

remote:        48 |

remote:        

remote:        at transpile (/tmp/build_d989cb6fdb4acc6a79775c1d6949d915/node_modules/babel-loader/lib/index.js:63:13)

remote:        at Object.module.exports (/tmp/build_d989cb6fdb4acc6a79775c1d6949d915/node_modules/babel-loader/lib/index.js:163:20)form.b39996c7cb4897273bcf.js from UglifyJs

remote:        Unexpected character '`' [form.b39996c7cb4897273bcf.js:525,32]

remote:        npm ERR! code ELIFECYCLE

remote:        npm ERR! errno 1

remote:        npm ERR! crowi@1.6.2 postinstall: `gulp`

remote:        npm ERR! Exit status 1

remote:        npm ERR!

remote:        npm ERR! Failed at the crowi@1.6.2 postinstall script.

remote:        npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

remote:        

remote:        npm ERR! A complete log of this run can be found in:

remote:        npm ERR!     /app/.npm/_logs/2017-10-04T05_14_16_105Z-debug.log

remote: 

remote: -----> Build failed


1.6.2が上がっているのだと思うのだけれど、herokuのことをわかってないから起こるような問題に当たってしまったのかしら。


どうすんべと思ってCrowiのgitter見に行って過去ログ漁っていたら、

“起動するときの env に関しては heroku 管理画面の configuration vars から見れると思います” という書き込みがあったので、

えーーーーーーーーーーーーっっと、、、


俺がやりたいことはこれで叶うのがわかった。

過去ログを漁るの大事だ。



問題はどうしよう

問題がherokuからの既存Appの取得にあるのかherokuへのupの仕方にあるのか内容にあるのかが全然わかってないので、えーーっと


こんなことがありましたよ、というのは伝えるか。

問題がどこにあるのかわかんないのが気持ち悪いんだけどこのモチベーションどうなの。



結論

heroku > configuration vars に FILE_UPLOAD local みたいなのをつけたら無事動いたよ、よかったね、という話。



ちなみに

gitterで指摘してもらった通り、heroku上にダイレクトにファイルを置くと、まあ、一定時間で消えるので、はい。。。

プランの問題なのかなと思ってたらそういうもんなのね。やろうとしたことなかったから知らんかった。


残念。





wrote 2017/10/02 15:43:07

読書辞書がわりの隔離wikiが割と有用だな~と気づくとかした


概要

知らない分野の勉強を始めるとまあ知らないから知らなければならないことがいっぱい出るじゃん。

それに対して「自分で用語集を書きながら読むとなんとかなるかも」っていうケースと、

思わぬ効能があったので書いておく。



勉強法

いままでやってきたことだと、こんな感じに勉強してた。


プログラム

自分でやる方法としてはとにかく一冊良さげな本を探して読んで実行して~みたいな感じなんだけど、

プログラミングだと逆引き辞書があるとすごく捗る。


欲しいものを作るために欲しいとこだけ読んで書いて失敗してをあらん限り高速にできるので。


あとは動いてるものを分解して変えるとかそのへん。



絵とかモデリング

ツールが難しくなければ題材を見つけて作りまくることで突破できる(ボブ理論)


ツールが難しい場合はうーん、できるだけ簡単なやつを探してトライ&エラー。

あと出来る人を見つけて聞く。

やったことない分野なんだけどひたすら専門用語と歴史的変遷と理論に溢れてるところがあって、

まあ手当たり次第でやってたんだけどどんどん背景が遠のいていく印象があった。


で、じゃあ勉強法を変えてみよう、ということで、まずは用語を整理する段階で、

適当な隔離wikiを作って使ってみている。


・辞書を作るイメージで、単語に対して意味をリンク先で書いていく。

・記事内で外部リンクを刺してもいいけれど、必ず自分の言葉で咀嚼した記事を残す。


あたりを指針にやっていて、これがまあ、物事の関係性を列挙するのにすごく向いているのがわかった。


ある理論とある理論を別に書いて、共通項はリンクで勝手に括り出されるので、見やすい。

学校のノートとかこういう取り方してもよかったのかもな~~とすら思った。


それ以外にも効能があって。



自作辞書はプロに採点されることができる

とりあえず誤った理解があるとここおかしいよこうだよ、って突っ込まれる。

wikiだから共同編集者がいればまあ確かにね!!


学習辞書とその採点サービスみたいなのをサービス化したら儲からんだろうか。まあいいや。



で、wikiである必要なくない?

ない。


自分の言葉で書くという学習工程と、書かれた辞書が欲しいだけだ。

採点はまだ副産物なんでもっと真面目に考えたら素晴らしいことになるかもだ。


余談なんだけどこれすごく簡単に作れるのでは。


リンクになるであろう文字列を書く

-> 右クリックで文字列の一部をリンクにする

-> リンク先を書く



みたいな所作を実現できるサイトがあればそれで良い気がしてきた。

ファイル吐き出しで辞書にできればそれで良いんだし。マイ辞書か。


wrote 2017/10/01 23:18:49

Shader関連で人間が欲しい知識とはどんなのか


概要

壁打ちのためにまとめる。



ShaderKitchenを作る時のモチベーション

・Unityにおけるシェーダの構造を解説すること

・シェーダの知識を得て、それをユーザーが再構成可能になること

・シェーダの知識をgithub上へと投稿でき、その解説を外部の人間が行うことができること


という3点に分解できる。


最終的には自分の手を離れて、github上で適当に成長していってほしい。ステークホルダーは自分なんだけど自分は学べればそれでいい的なポジ。



今のところ考えている知識の階段

1.Unity上でのシェーダのフォーマットを知る

2.今まで存在したシェーダ(PBR以前)について、その式の意味を、用語と一緒に解説する

このパーツはあのシェーダのあの部分、とかの、実質の機能的な意味での先祖と子孫みたいな関係を露わにしたい。

またそれを遡って参照可能にしたい。


3.同様のフォーマットでUnityのstandardShaderの解説や、ユニティちゃんトゥーンシェーダの解説を行う

4.適当な知識人に自慢のシェーダを披露してもらい、その解説を書く


というような感じでコンテンツを揃えていって俺はいろいろわかってラッキーみたいなことを考えていたんだけど、

ShaderForgeとかAmplifierあたりのせいで懸念がある。



しかるに困っていること

ShaderForgeとかとシェーダのプログラム学習の相性が最悪に悪い気がしている。

こう、ShaderKitchenは、シェーダを直書きすることそれ自体は目的ではないんだけど、それでもコードを元に解説をしようとしている。

で、ShaderForgeとかで書かれたシェーダコードから意図を推察するのが、これがものすごくしんどい。


あのへんのツールは

・1~2までを様々な経験で理解した人が

・それをコードなしに表現すること

を達成するために存在している感じがある。


なので、あれらの生成されたコードを見てもさっぱり勉強にならん。


-> どちらかというとShaderForgeとかで吐いたコードを綺麗にガッチャンコして数字シェーダ名を解明して云々みたいな

逆アセンブルが必須になる。


というのがあって、うーーーーん、、

・コードを元にシェーダを解説しようという試みを続けていいのか

-> 絶対に必要だという直感があるのでYes


・んでShaderForgeとかとどう付き合えばいいんだろう

-> なやみどころ


という感じ。


wrote 2017/09/21 22:14:59

SublimeText3正式版が出たね + デフォでpackage controlが動かない話


概要

build 3143では、package controlっていうSublimeText用のパッケージマネージャ(プラグイン入れる君)の扱いが面白くて、

インストールするも効かない(その旨も特に通知されない)という状態になっている。


インストールしてもpackage control使えなくてビビった。



必要なワーク

1.SublimeText build3143以降をDL

2.wbondさんのとこからpackage controlをインストール

3.インストールし終わったらSublime Text > Preferences > Settings を開いて、

{

"font_size": 12,

"ignored_packages":

[

“packageControl”,

"Vintage"

]

}

となってるとこからpackageControlの行を消す。


これで使えるようになる。



同じような目に遭った人

居た。

https://forum.sublimetext.com/t/no-package-control-in-v3-build-3143/31363

wrote 2017/09/19 16:00:38

iOSDC2017行ってきた


概要

これ

https://iosdc.jp/2017/


自分が参加したのは16, 17の二日間。


全部書いてると死にそうになるので印象に残ったところとか素晴らしいと思ったところをダイジェスト。



16日


モバイルアプリで困らないエラーハンドリングとロギングのベストプラクティス

guard 節で書いてあるコードに対して、Analyticsのfatalな感じのログを入れておく、という部分が素晴らしかった。


・複数人開発をしていると、「これは絶対起こらんやろww」みたいなことが起こる。呼ばれるはずがない条件で関数が呼ばれたりとか。

・その異常を、エラーを生み出すよりも先に異変として察知するために、Analyticsを使う

というのの具体例で、他に類をみないアイデアで素晴らしいと思った。


応用が利きそう。



Implementing Music Playback on watchOS

いろいろなAPIやそれらのサウンド面での動作の話が面白かった。特にアプリケーションのforeground -> bgでの寿命まわりで、

サウンドをストップしても死なないで欲しいんだけどそのうち死んで欲しいみたいなニーズがAppleWatch app にもあるんだなあというのが参考になった。

その実装方法も含めて。


Xcode Source Editor Extensionの世界

この日一番輝いてた(独断)


「愚痴るだけなら誰でもできる

高い壁があったら登るのが我々エンジニア」


なんかどっか自分ちの壁に貼っとこうかなと思った。人に言わされると嫌な言葉だとは思うんだけど、自分で言う宣言としては最上。


Xcodeのプラグインを作るときに調べようと思っていたことがすべて網羅されている。


資料のアプデ報告TweetをXcodeプラグインから行うという離れ業すごかった。

https://speakerdeck.com/takasek/20170916-number-iosdc


あとこの日この公演のあとにルームCにトートバッグを忘れたのは俺でした。

運営の人ご迷惑おかけしました。無事回収させてもらいました。助かり~



17日


アイコンや画像の配置をCIで自動化する

Sketch.appのコマンドラインツールを使ってデザイナー -> CI -> 実装(エンジニア) までをシームレスにつなげていて素晴らしかった。

各所での処理も最小限っぽい。


で、これらの先駆者のおかげでUnity用にもプラグインを作ることができた。

Sketchで作った全画像をUnityに取り込む

http://sassembla.github.io/Public/2017:09:17%2015-07-34/2017:09:17%2015-07-34.html


興味深かったのが、全体のフローが仕上がった後に問題として残っている部分の紹介で、

名前付けやそれらの前提ルールの整理について、という感じで、


治安が良くなると次は文化的な問題の解決に向かっていく、というのが素晴らしいなあと思った。


CoreMLでアイドル顔識別アプリを作ろう

MLがらみのファイル生成に関するいろいろな関連性がわかって凄く助かった。



15分でわかるバックグラウンドアップロード

BackgroundTransferServiceについて言及してくれていて、自分たちでデータアップローダみたいなものを作るときに大いに参考にさせてもらおうと思う。

timeoutIntervalForResourceのデフォが1Wだった話面白かった。



サポート効率を上げるログ収集環境の構築

独自enumを作れ! という感じで面白かった



iOSDC Japan 2016 の賞金を放置しておくと1年でどうなったか?!

完全にビットコインの話題だった。最高。たかりたい。



会場インフラLT

業者さんがらみの壮絶なスケジュールを踏破して会場ネットワークなんとかしていたのものすごい。

お陰さまで快適なネットワーク環境で真剣に話を聞いたりビールを飲んだりすることができた。




終わりに

最高だった。来年もまた行きたい。

wrote 2017/09/17 23:56:39

Sketchで作った全画像をUnityに取り込む


概要

iOSDC2017でsvgファイルから画像群をexportするsketchtoolというコマンドラインツールが紹介されてて、

アイコンや画像の配置をCIで自動化する

https://iosdc.jp/2017/node/1442


これはsvgファイルをそのまま使えないUnityとかでも本当に利益がある発表だったので、Unity向けにやってみようみたいなやつ。



Sketch

macでベクターいい感じに扱えるアプリ。凄く軽量、安定してて便利。sliceの概念は見事のひとこと。


Sketchこれ

https://www.sketchapp.com


で、sketchtoolはこの.appの中に含まれている。

Sketchで作成したデータから、好きな単位で画像を取り出すことができる。素晴らし。


sketchtoolの紹介

https://www.sketchapp.com/tool/


目指す挙動

1.UnityのAssetsフォルダにSketchファイルを放り込んだらインポータが起動してexportを実行して画像を吐き出す

2.Sketchファイルが更新されたら、再度インポータが起動してexport処理を実行して画像を吐き出す

3.すでに存在する画像を上書きする場合はそのimport設定を模倣する(これはUnityがやってくれるんで自動的にできそう)

これらができると、Sketchで画面単位だったりパーツ単位でsvgで素材を作成し、そのsliceで解像度を指定し、

そのファイルをUnity側で使用、Sketchファイルに更新があれば自動的に変更に追随できるようになる。


ファッキン便利。



できたもの

sketchファイル放り込むと中身のsliceをファイル名フォルダ作ってexportしてくれるやつできた。


SketchFileImporter

https://github.com/sassembla/SketchImporter


使ってるとこ

SketchImporter from toru_inoue on Vimeo.

wrote 2017/09/17 15:07:34

MiyamasuでUnityTestを実機実行できるようにした。


概要

Miyamasu Test Runnerをアップデートして、Unity5.6以降のテストを実機でも動かせる + 実行結果取得できるようにした。

サンプルシーン起動するといきなりこんな感じになる。


DJxYJzuUEAA1jBa.jpg


画像はiPhone実機上でのテスト実行と結果みたいなやつ。ログのところはコピーできるので端末からでもいろいろできる。


エディタ上からは、Unity自体のTestRunnerを使って実行できるようになっている。

スクリーンショット 2017-09-15 23.33.48.png



Miyamasu

https://github.com/sassembla/Miyamasu


リリース。UnityPackageもあるよ。

https://github.com/sassembla/Miyamasu/releases/tag/0.6.0



動機

5.6から、まともな非同期テストが書けるようになった(二千何年の話をしてるんだ)


Unity5.6で非同期テストするときの基本的人権が保護されそう

http://sassembla.github.io/Public/2017:03:09%2019-09-05/2017:03:09%2019-09-05.html


で、これはUnityTestっていうAttributeをつけることで実現できてたんだけど、なんと実機上でテストを実行するパスが無かった。

Editorにつないで実機に送り込んで実行、ってやってると、なんだ、その、ダサい。


というわけで、EditorでもRuntimeでも実行できるようにした。


また、実機実行に際して、GUIを作るのがダルかったのでUUebViewっていうHTML書いたらGUIが出るやつを使っている。

動的にHTMLコンテンツを足していってオートリロードで動かす、みたいなのができた。


テスト結果を表示するところに使われている。具体的にはこんなコード。


https://github.com/sassembla/Miyamasu/blob/master/Assets/MiyamasuTestRunner/Runtime/MainThreadRunner.cs#L117

public void AddLog (string[] message, Recorder.ReportType type, Exception e) {

    var icon = "pass";


(中略)


    var error = string.Empty;

    if (e != null) {

        var id = Guid.NewGuid().ToString();

        error =  @" button='true' src='" + Base64Encode(e.ToString()) + @"' id='" + id + @"'";

    }

    

    logList.Add(@"

        <bg" + error + @">

            <textbg>

                <contenttext>" + messageBlock + @"</contenttext>

            </textbg>

            <iconbg><" + icon + @"/></iconbg>

        </bg><br>");


}

HTMLを追加するだけで画面にこんな感じにコンテンツが出るようになる。


スクリーンショット 2017-09-15 23.29.07.png


失敗したテストのとこに赤いの出るようにしたら便利だった。


テストコード

UnityTestがIEnumeratorを扱うようになった都合上、次のような形で非同期テストが書けるようになった。


一定時間のあいだ、条件が満たされるのを待つ。時間内に満たされればOK、ダメだったらTimeoutExceptionが出る。


https://github.com/sassembla/Miyamasu/blob/master/Assets/SampleTests/SampleTest.cs

[MTest] public IEnumerator Timeout () {

    var obj = new GameObject("runner");

    IsNotNull(obj);


    var runner = obj.AddComponent<Runner>();


    yield return WaitUntil(

        () => runner.n == 100,// too much.

        () => {throw new TimeoutException("not yet. runner.n:" + runner.n);},

        1//sec

    );

}


yield return WaitUntil() で非同期待ち出来るのいい。


Assert系はUnityに組み込まれているNUnitをロガーでラップしたものを用意した。

といっても全部ラップするの面倒臭かったので、まだログが出ない関数がある。(定義ジャンプすればわかる


そのうち全部ラップする。あと半分くらい。一括置換サイコー!



今後

AutoyaのテストもMiyamasuで書いてあるので、更新して動かせるようにする。

体感で1.5倍くらい高速になった。あとGUIがついたので色々楽に。


GUIからのテスト単体の再実行、Slackと連携してテストログの送付(誰かに送りつけたい)、Slackからのテスト送り込み、などをやっていきたい。


wrote 2017/09/15 23:36:32

UUebView ドキュメント(途中)


概要

Standalone WebView for Unity なこれのドキュメントを書かねば。

UUebView

https://github.com/sassembla/UUebView-freeversion


このページを草稿とする。



使用できるWebコンテンツについて

HTML一択。


実際にデモで使っているhtmlのサンプルはこんな感じ。

https://github.com/sassembla/UUebView-freeversion/blob/master/Assets/Sample/Resources/items.html

CSS、JSは一切効かないどころかパースできない気がする。

そのうち無視するようにするかな。

UUebViewの制約として、Unityの持っているAnimationやらイベント、uGUIレイアウトの機構でだいたいのことはできるので

Unityゲーム内でWebView代替としてAppアプデ無しに動かすに足ると判断したため、JS、CSSはサポートされない。



HTMLのルール

・HTMLタグはここにあるタグのぶんは適当に使える。

https://github.com/sassembla/UUebView-freeversion/tree/master/Assets/InformationResources/Resources/Views/Default


・DOCTYPE以外のタグはすべて小文字で書く。

なんかhtml5wayらしいんでそれで。パースも楽になるんでそれで。

http://www.xml.vc/HTML5/kiso/rule.html

これの、HTML構文例に出てくるようなのをサポートしている。


・DOCTYPEはなくても良い

・DOCTYPEでサポートされているのは、独自に作った uuebview タイプのみ。

hrefをつけて独自定義タグの設定ファイルをwebかresourcesかAssetBundleから読み出すことができる。

サンプル items.html ではresourcesから読みだしている。


・title, headは完全に無視される

・bodyはあってもなくてもいい


・使えるAttributeは以下

id(string)

要素にidを振ることができる。


src(string)

要素が画像系であれば、画像を展開する


href(string)

要素をボタン化した場合、イベントのパラメータとして使われる。


align(left, center, right)

要素の整列を行う。


また、UUebView独自で以下のAttributeを使ってイベントを制御することができる。

button(true, false)

要素をボタンとして扱い、クリック時にイベントが着火するようになる。idがあればイベント着火時にパラメータとして渡ってくる。


listen(string[, params string])

パラメータに他のタグのidを記述できる。そのidが振られた要素がイベントを発効した場合にhiddenを切り替える。id要素は,で箇条書きできる(ようにしたい)


hidden(true, false)

要素の表示/非表示を扱う。falseを指定すると初レンダリング時は非表示となる。



Viewの取得

UUebViewComponent.Getなんちゃら(ドキュメント書き途中)



ハンドラ

複数のイベントハンドラがIUUebViewEventHandler型で定義してある。

OnLoadedとか。(ドキュメント書き途中)


イベントの発効

画像、リンクはUnityのGUIとしてのクリック機能を持たせることができる。

タグにbutton=‘true‘ とか書けばいい。



Viewへの要素の追加、削除

でっち上げのTreeQueryLanguageを使って要素を編集することができる。

構文

タグ/子タグ:インデックス数値/目標タグ

e,g,

body/child:0/img


などのように書くと、

<body>

<child>

something

<img src=“”/>

</child>

<child>

<img src=“”/>

</child>

</body>


太字の要素にヒットする。

これqueryなの?っていうと疑問が出てくるんだけどまあほら、暫定だから。



末尾に追加するなら(ドキュメント書き途中)

特定のタグの要素の末尾に追加するなら(ドキュメント書き途中)

削除する場合(ドキュメント書き途中)



wrote 2017/09/14 17:47:51

C# Job Systemを使ったUnity流マルチスレッドプログラミングの話


概要

CEDEC2017 マルチスレッドで動かすための書き方 + コンパイラオプションのはなし。



DataOrientedProgramming

データ構造を分離してぶん投げる


MonoBehaviour -> structMonoBehaviourみたいなのを作った


JobComponentSysytemを実装



GCなし

NativeArrayの導入

うおーーーNativeArray入ってるのか

var src = new NativeArray<float>(500, Allocator.Temp);

src.Dispose();



安全

エラーで指摘してくれる

例えば依存した順番のジョブを順番指定なしで実行すると、依存書けよってえらーになる。



高速な新コンパイラ

Mono > IL > JobComp > DomainModel > Opt > LLVMからExeが出力される



IJobXインターフェース

単体のジョブ、毎フレームExecute関数を実行してくれる。


Scheduleで開始して、JobHandleを返してくるので、次のフレームとかでCompleteでまつ。というのが使い道。


例えばマッシブなアレイのコピーとかを別スレッドに入れることができる。

ネストもか~。



今後、いろんなものがスレッド内で使える様になるぽい。transformはすでに扱える。

IJobParallelForTransformとかがあるぽい。一般化どうなるんだろう。



Jobコンパイラ

ここまではJobシステムの話。

で、新コンパイラのサポートをうけるには、[ComputeJobOptomization(Accuracy, Supprt)]というのを書けばいい。


新Mathライブラリとか

mathf -> mathというのを作ったらしい。



今までのプログラムがどう変わるか

MonoBehaviourで書いてたキューブの回転を変えてみる


どれくらい高速化できるか。


その1

MonoBehaviour大量 -> Managerが単一のMBで一気に回す


その2

TransformAccessArrayというのを使って、ParallelJobで放り込む

これもいいんだけど、作り方を変えてみる


その3

MB -> IComponentBehaviour

ComponentSystemという方を継承して、ComponentArray<ScriptBehaviour>を持たせて、[InjectTuple](全部のInjectTupleAttrがついてる項目をUnionにする


ComponentSystemというのがComponentを放り込んでいい感じに動かしてくれるマネージャ。


その4

Jobにするために、 JobComponentSystemを継承させる。で、これでPararllelForで動かせる様になる。



使い所

距離計算、AI影響マップの生成に使えたりするよ、と。

あとは判定のあるエフェクトとかができそうな気がする。


wrote 2017/08/30 13:38:24

Kill WebView


概要

Unityでゲーム作ってて一番アンニュイになるところってどのへん?


自分はWebViewを組み込まないといけないあたり。

お知らせ画面とか、そのへん。



実機でないと動かなかったりするじゃん?

Unityなのに。

HTMLとJSとCSSを使わないといけないじゃん?

Unityなのに。


あんだけ沢山使うのにネイティブプラグイン必須っていうのが耐えられない。


遅い。



他にも色々とあるが、ということで「殺る気が溜まった」ので、できたよ! 


みるがいい!!

これが!! WebViewを殺すモノだ!!


UUebView-freeversion

https://github.com/sassembla/UUebView-freeversion



UUebView is 何

UnityのコンテンツをHTMLで書けるようにする奴。

より具体的に言うと、


・uGUIからHTMLタグを生成

・HTML記法でコンテンツを作ると、良い感じにViewを吐き出す

やつ。


こいつによって、JSやCSSを書くことなく、HTMLとuGUIパーツによってGUIを作り出すことができるようになる。

そして自由な頻度でviewの内容を更新することができる。


作り方を紹介するぜ!!!



1.適当にuGUIで雛形を作る


UUebView.png



これらは次のような感じのパーツ名にしておく。


UUebView-2.png



2.Window > UUebView > Generate UUeb Tags From Selection する

Hierarchy上で選択した項目がHTMLタグになる。



3.HTMLファイルを用意する

こんな感じのやつ。


UUebView-6.png


すると、良い感じにuGUIの中身がhtmlで書いた内容の通りに伸びたり縮んだりしてUIを生成する。



UUebView-3.png


テキスト背景に色がついてるとこは、そのまま色的に対応するuGUIのパーツを使って生成される。


中に入る文字の位置や形状が、uGUIの状態に従う。


これは表示の有無も例外ではなくて、

例えばnewbadge要素とかは、書けばnewのアイコンが出るし、書かなければアイコンが出ない



仕様

・レイアウトはuGUIで生成した雛形に準じる

縦に伸びたりコンテンツの横に置かれたりとかはすべてuGUIで設定される感じになる。

・HTMLのように、同じタグを複数使うことで表示する項目数が増やせる

何を当たり前のことを、っていう感じだけど、良い感じに項目のレイアウトをした上でコンテンツを増やすことができる。

レイアウトのことを気にせず、コードを書かずにコンテンツを自由自在に増やせるのだフハハハハハハ


・uGUI経由で、自作タグに独自でフォント指定したり画像指定したりすることができる

こういうのWebComponentsでもJS+CSSとかでできるけどUnity内ならぶっちゃけこれでよくね?


・aとかimgとか、基本的なタグは組み込みで用意されているし、自作することもできる

できる。君だけのry


・イベント機構あり

画像に対して「これはボタンだ」という設定をしたり、すべての要素にidを振り、クリックイベントなどを取ることが可能。

もちろんリンクを触ったら別のページロードしたりとかね。

あとスクリプトつけて自前でなんでもできる。回転するパーツとか光ったり云々とかね。


・もちろんhtmlをサーバからDLするように書けば、、あとはわかるな?

そう、これはWebViewなのだ。



利点

・軽量

・プラットフォームを選ばない

・端末差なし

・JS、CSSが書けないのでそれらの知識がいらない

・必要なHTMLの知識が少ない

・OSバージョンアップで壊れたりしない

・好きなタイミングでタグを更新したり追加したりできる

説明してないけどできる。



欠点

・動的にコードを足すことができない

iOS等の制約を超えるものはできないんだけどこれはまあ従来のものでもできない。



予定

HTMLタグ生成をもうちょっと便利にしたりTagsをAssetBundleからDLしたり、movieタグとかを組み込んだバージョンを商用で作り中。

あと汎用アニメーションはUnityのデフォルトのもので解決できるかどうかを試験中。それがあるとアニメーションはだいたいどうにかなる。


現在リポジトリからDLできるものは、商用になっても無償で使えるフリー版。


商用がリリースされてもそのまま使えるようにするつもり。




wrote 2017/08/28 17:26:15

いいことあったのでアロセールArrowCell っていうライブラリ作った


概要

これ。

ArrowCell

https://github.com/sassembla/ArrowCell



なんに使うの

遠く下の階層に離れたゲームオブジェクトの持っているコンポーネントの内容を更新する。

Inspectorへのセットとか一切無しに、上位階層から下位階層のコンポーネントに干渉できる。



名前の元ネタ

弓矢のかみさま(主観)。スペルは違うよ。

上から下に対しては無敵なのでこんな名前に。


Pros

遠く離れたコンポーネントを疎結合にいじれる。

指向性があり、KVO的なやつではないので、探しやすく捨てやすい。

動的にオブジェクトを作りまくる場所だと特に重宝する。

(今後エディタでビジュアライズされる。)

失敗しても何もおきない。(それはそれでやばい)

キャッシュが効く。



Cons

エディタ上でぱっと見、なぜこのコンポーネントが変更されるのかがわかりにくい。(エディタで線引いたりする予定)

キャッシュを上書きするタイミングがない。(そのうちなんかする?)


作成理由

いいことあった。


wrote 2017/07/29 23:34:50

ちびっこ生まれたやったー!


概要

予定日ど真ん中にちびっこが生まれた。大変可愛い。よかった。



wrote 2017/07/29 23:33:37

Autoya Informationを仕上げる


概要

なかなか大変なので記事にすることでモチベを上げる。という不思議な試み。


Autoyaっていうフレームワークがあるんだけど、まあ、そこで、WebViewを使いたくないんだよ。


Autoya

https://github.com/sassembla/Autoya



で、このInformationという機能で、

WebViewなしでhtml/markdownをuGUIパーツを使って描画する

みたいなことをやっていて。


その中でそろそろリファクタリングしようなみたいな感じになってきたので、そのまとめとしてこの記事があるっていうね。



心意気

WebViewを使わずにそれっぽいビューを表示したい。

markdownとかhtmlの描画ができると嬉しい。

その際にjsは完全に無視、cssは別の方法で実装、レイアウトにはUnityのuGUIから独自タグを作り出してそれを使う、という感じに殴りつけている。



なぜWebViewを避けるのか

・イベントフックが毎回面倒い

・遅い

・たかだかお知らせとかを出すためには機能過多

・遅い

・イベント入力位置とかビューの位置情報とかをUnity側と同期するのがしんどい

・遅い

・プラットフォームを跨いだ実装が存在しない

・遅い

・各種exploitの源になることができる

・遅い

・機能の初期化や更新などがいい感じに重い

・あと遅い


などの理由があり、あと根本的に遅いため、WebViewへの依存を殺傷することを真面目に考えるに至った。



既存構造

md/htmlparseしてLayout(レイアウト計算)する

・Layout済みのビューをMaterialize(実体化 = uGUI化)する


という感じで、まずLayout -> Materializeという順番で動かすことだけを考えて実装していた。

まあこれがうまくいかないケースが出てきた。



Problem1:Layoutにロード後の素材の情報が必須

画面幅だけを与えた画像(width=100%、height指定なし)とかに対して、

widthを画面幅で出すことは容易なのだけれど、画像の高さが未指定なので、高さを自動的に算出することができない。


仕様的には、画像のwidthが100%であれば、heightは画像のアスペクト比に応じて決定される。

このため、画像のアスペクト比が必要になる。


で、Layout機構ではまだ画像をDLしてないので、困った、っていう。


P1解決策

Layoutを遅延させて画像高さを得るか。まあそれで損することは特にないような気がする。

・Layoutにローディング要素のローディングを盛り込む

・Materializeの代わりにFocusみたいな概念を持ち込んで、指定のポイントから画面高さ分を実体化する


というような感じでいける気がする。

座標系の変更点がLayoutだけに場が閉じていれば、再度Layoutが発生したコンポーネントから先だけを再Layoutする、っていうのも容易なのでは。


ローディングがかかるチャンスは一度のほうがいい(分割ローディングする価値は無い)、という感じなんで、まあいいか。

・Layoutが完了したらハンドラが着火される

みたいな感じになる。


Problem2:いろんなハンドラについて解決する

このへんの細かいパラメータの決定条件を書かんとな。すっげー多いんだよなこの辺。

まず列挙するか。


・イベント

画像、リンク、タッチなどが仕込める。

仕込めるが、外部からどのように触れるようにするか、っていうのはまだ考えきれていない。

ビューに対してイベントを仕込んでおく、みたいなのとは別に、このビューに対してこのイベントが起こったらこうする、というのを渡せればいいと思っている。



・階層間距離処理

要素の階層構造に対応して隙間を適当にセットできる。 で、まあ、ようは、css。

・使用リソース指定

特定のAssetのセットを対応させることができる。

画面ごとに、「このUIの時に表示させる画面はコレ」みたいなのがセットできる。

階層間距離処理とかもAssetにしてしまうと良さそうな気がするな~。


よくまあ作ったもんなんだけど、これだけ広範囲に機能が存在するとほんとに使えるのか疑問符がいっぱい出てくる。

すべてハンドラのていを保っているんで、まあ内部的な拡張は容易。外部公開も容易。


でも外部公開はあんまりしないだろうな~~カスタマイズ性をAPIで表現しすぎると設定項目多くて使いづらい。


P2解決策

イベントに対して

・画像、リンクのどちらにしても、urlを受ける。

-> 発行されるメソッドの型 = ButtonとかLinkとか をenumで持つようにして、実行されるメソッド種を一個で済むようにすんべ。

-> uGUIのイベントにしちゃうのがいいかな。インスタンスどう渡すかな~。呼び出し元が限定できればいいだけだったらuGUIのイベントの必要ないんだよな~。

複数のビューを同時に出す、とかも視野に入れときたいので、それを考えると、ビューのインスタンスを取り出す時にハンドラをセットしたり、ハンドラを後からセットしたりできるといいのか。

まあやっぱAction<EventSourceType, string>一発で済むな、イベントにする必要ないや。


使用リソース指定

・階層構造に対してAssetを割り当てられるといいのかなあ。

Prefabに階層構造値を指定できる、とか?

なんらかの形でAssetが出力できればいいのか。

-> html -> view -> htmlへと再分解できるコースが存在することに気がついた。

具体的には、uGUIでビューを作る -> そこからPrefab要素を作ると、その要素をhtmlで記述して生成、レイアウトできるようになる。

本機能は、ぶっちゃけ、HTMLでUnity GUIを表示するブラウザ機構みたいな感じになる。

これがCSSの代わりだな~~。



・uGUIでGUIを作る -> HTMLでそのGUIを配置したりパラメータ出したりできる

Prefab雛形をキャンバスに並べる -> パラメータ設定

-> ビュー名をつけて保存、ってやると、

-> 階層を見て階層情報をPrefab化

-> 要素それ自体を別Prefabとして分解保存

-> リソース名フォルダがどこかに爆誕するので、それをAssetBundleにしたりすることができる。

-> リソース名 = ビュー名なので、Load時に名前を指定することで、DLしたりResourcesフォルダから探したりできる。



Problem3:Container Prefabがウザい

現状は特に意味がなく、無くせる気がする。うん。設定しないでも行けるように変更するか。

ContainerPrefabはなくても動かせる

P3解決策

Container Prefabを読み込む実装を消す。

->できた。



リファクタリングが終わっていい感じ

Layout, Materializeが綺麗に分割された。


depthを簡単に得るために、Tagに関しては、Layout開始時にすでに値になってしまっていてもいいのかもしれない。まあ後回しで良さそう。

それか単純にstaticなdepthを得る関数を用意すれば良さそう。


今後

AssetBundleの群が複数必要。

・viewNameに対応するAssetBundle群

・html内で使用される画像とかを格納したAssetBundle群

後者はInformationの枠組みを超えるAssetBundleなので、どうしようかな、頑張ってくれ的な。


前者はサポートをしたい。

具体的には、

・AssetBundle化の機構を持たせる

・DefaultとspecificをそれぞれAssetBundleにすることができる

・それらが読み込まれる(リストみたいなものを渡しとく必要はある?

できればAssetBundles機構への依存を少なくしておきたいんで、Informationから直で使うのは避けたい。

、、、


まあ悩もう。




wrote 2017/06/28 19:30:54

publi.shの代替を作る


概要

publi.shとは、今このブログっぽいものをrtf -> htmlへと変換してるツール。

まんまshell。


で、さすがに拡張が無理なのと、なんらか見やすいようにしたいね~という思いがあり、

式年遷宮を考え中。


現状のpubli.sh(というかhtmlnize.shとindexize.sh)

https://github.com/sassembla/Public/blob/gh-pages/publi.sh https://github.com/sassembla/Public/blob/gh-pages/htmlnize.sh

https://github.com/sassembla/Public/blob/gh-pages/indexize.sh


既存仕様のいろいろ

rtfベース

記述はrtf or rtfdで行なっている。というかMacのTextEditっていうアプリが高性能で、

画像だろうがレイアウトだろうがなんだろうが自由にサクッとなんとかしてくれるんで、そのへんに依存している。


絶対にhtmlを書きたくない。強調ぐあいGUIからえられてなんぼだ。



html変換

htmlnize.shってのでやってる。

https://github.com/sassembla/Public/blob/gh-pages/htmlnize.sh


TextEditで出力したrtfをhtmlに変換するところはshellで行なっている。

特定のフォルダにrtfを入れた状態で変換shellを走らせると、rtf/rtfd2htmlが走る。

画像が一切含まれないrtfはそのままhtmlへと変換される。

画像が含まれるrtf = rtfdはこれもともとフォルダ的な扱いでデータを保持するので、

html化した際はフォルダが露出し、使用している画像などが画像として出てくる。


で、rtfd->html化された場合、html内のパスが自動的にフォルダ内の画像パスを指すようになっている。

これによって、アップロードされたあとの画像パスがいい感じになる。



自動インデックス作成

indexize.shってのでやってる。

https://github.com/sassembla/Public/blob/gh-pages/indexize.sh

html化された記事からタイトルを取り出して、その日付とかを元にリンクというか記事一覧インデックスを作成する。

無理やりやってる。



バージョン管理

publi.shの対象パスをgithubで管理してるので、まあ、楽。



競合というか制作動機

octpressとかまあほんとにそのへんいろいろあるんだけど、ブログである必要はないという異様な需要に基づくいらない機能がいっぱいあるんで、

それらをカスタマイズするのが辛いので作った。



つづく。


wrote 2017/06/28 15:43:17

Dasya:http+ws+tcp portablebackend


概要

ポータブルなバックエンド

= httpとwsとtcpが喋れるサーバが欲しい。


かつ、このバックエンドで適当なパターンマッチ積んで、リクエストやらイベントに対して自動で適当なレスポンスを返せるようにしたい。

UIとかはUnityからぶっ叩けるといいのでは的な。


簡単でいいんで作ろう。



扱うイベント

特定のhttpリクエスト、tcpで飛んでくるパケット、wsで飛んでくるバイナリとか文字列に対して、


.NETCoreでいいや

動けばいいやってレベルなんでざっくりやろう。

Unity2017とかにも標準でexe入ってるし。



機能の想定

tcp, http, ws を扱いたい。で、

・httpはHttpServerが動けばよし

・tcpはTcpServerが動けばよし

・wsは上記が動けばよし


という感じで、さらにtcpに関してはまあ特になんかせんでもDisquuunとかがあるんで、

RedisとDisque(そのうちRedisにプラグインとして吸収される)があるんで、機能を追加する場所を綺麗に提供できればよし。


Status:そのうちつくる

Motivation upgrading…

https://github.com/sassembla/Dasha

wrote 2017/06/27 10:38:48

WebuSocketのテストをポータブルにする + tls1.2


わすれてたんだけど、nginx-lua側もtlsやらんとな。

https://github.com/openresty/lua-ssl-nginx-module



概要

これもまた式年遷宮。


tls喋れるWebServer欲しい

・ついでにwssも喋れるWebServer欲しい

という感じで。


Unity2017からは.netCoreのバイナリも入ってるんで、それでフルに書こうかな~~と思ったんだけど、うーんん、まずは動作する別環境を作って、それに追いつかせよう。

というわけでまずは見本作成、nginxでの手元でtlsなhttp + websocket な話から。

-> 準備が思ったより大変だったので、うーん、最後のチャレンジとしてルータの整理整頓を行う。悲しい。




TLS導入の話

let’s Encryptな。

https://www.nginx.com/blog/lets-encrypt-tls-nginx/



nginxの設定

日本語でわかりやすく。

https://heartbeats.jp/hbblog/2012/06/nginx06.html

で、それらが整った上で、netCore上でとりあえずhttpとwebsocket返せるやつ書こう。



そういえば、WebuSocketでのドメインの除外設定について

特になんもせずに流してる気がしてきたぞ。ガバガバだぞ。

https://github.com/sassembla/WebuSocket/blob/master/WebuSocket/WebSocketEncryption.cs#L73


なんとかしよう。



メモ

certbotってのを使うといい感じっぽい。

https://certbot.eff.org


どんなサーバ使ってるんだっけ? -> ubuntuなんだけどvどれ

cat /etc/*release


-> 16.04.2 LTS


ふむ。


$ sudo apt-get install software-properties-common

$ sudo add-apt-repository ppa:certbot/certbot

$ sudo apt-get update

$ sudo apt-get install python-certbot-nginx 

ふーむ、一行目からこける要素がある。apt-get update したらいけた。これ以降は動作。


Geographic area: 6

Time zone: 78



で、ここからがcertbotの動作。

sudo certbot --nginx


で、

No names were found in your configuration files. Please enter in your domain

name(s) (comma and/or space separated)  (Enter 'c' to cancel):kissaki.tv

ふむ。


nginx: [error] invalid PID number "" in "/run/nginx.pid"

Cannot find a VirtualHost matching domain kissaki.tv.


あ、なんか前提おかしいっぽい。nginx動いてるといけなかったかな?

なんか起動しっぱなしのnginxのpidがおかしいのかな。

-> nginxの状態がおかしいっぽい。ふむ?

-> リンクがおかしかった。デフォルトでnginxっていうリンクが存在してるぽいんだけど、自分の構成したnginxのパスを踏んでない。

このexeはなんかletsencが作っちゃってるっぽいな。なるほどな?


・restartには失敗してるんだけどもうconfは変わってるんだろうか?

なんかletsencは別のnginxをいじってるような気がしなくもない。


とりあえず本家で入ってたnginxを停止した状態で試してみよう。


-> エラーは出なくなった。が、

Cannot find a VirtualHost matching domain kissaki.tv.


とか言われる。ふむ。

なんかいろんな前提がありそうなんで、bareなubuntuからやってみよう。

Bareなubuntuでリトライ

apt-get install python-certbot-nginx

のとこで、nginx入れてるんだなあ。これと前提が合わせられればそれでいいか。

で、ubuntu + certbotだとバグがあるみたいな? まじ?

下記で触れられてるのと同じことが起きてるっぽくて、うーん。最近か。centosでやってみよう。

https://totoshko88.wordpress.com/2017/06/11/letsencrypt-certbot-ubuntu-nginx/


Bare centosでリトライ

はい。とりあえず動かしたい。


yum -y install wget

wget https://dl.eff.org/certbot-auto

chmod a+x certbot-auto

./certbot-auto --nginx


で、依存いろいろ入れて、

Saving debug log to /var/log/letsencrypt/letsencrypt.log

The nginx plugin is not working; there may be problems with your existing configuration.

The error was: NoInstallationError()

ふむ、、、なんかあやしい。


こっちではnginxが入ってないな~なるほど、動かしとけ的な前提なのかな?


いろいろ読んで試そう。


https://digitz.org/blog/lets-encrypt-ssl-centos-7-setup/


https://certbot.eff.org/docs/



別軸

How to setup NGINX with automatic HTTPS in Docker

https://tevinjeffrey.me/how-to-setup-nginx-proxy-and-lets-encrypt-with-docker/




nginx側の記事

https://www.nginx.com/blog/lets-encrypt-tls-nginx/



Certbot

main

https://certbot.eff.org/#ubuntuxenial-nginx

doc

https://certbot.eff.org/docs/



おっdockerに対応してる記事あった

http://qiita.com/setouchi/items/b3a78cb396ae6e58b84b

wordpressかー



Running with Docker

うーんドキュメントを読もうと言う感じだ。

https://certbot.eff.org/docs/install.html#running-with-docker



docker で全自動 Let's encrypt

ほうほう。


http://qiita.com/kuboon/items/f424b84c718619460c6f


続きやってみよう。



・対象のドメインへのアクセスができなかったから動いてない説

・ARecordのセット

https://muumuu-domain.com/?mode=conpane&state=custom


・ルータの解放

https://www.akakagemaru.info/port/wsr-2533dhp-portfw.html


あたりがありそう。なるほどって感じ。で、ルータのパスを失ったので、どうすっかな。再設定か~。



最終的に欲しいものは

nginx + tlsを動かせる場所。

awsで構築するか。



nginx

あ、そういえばdocker作ったわ。

dockerでの動作な必要があるのかな?


aws

ec2に導入すれば良さそう、これはapacheの例なのでまあ読みかえでいけるかな。

https://qiita.com/MashMorgan/items/56498f276c54406b1928





wrote 2017/06/25 20:58:14

Nginx-luajit-wsの更新と整理整頓


概要

手元で動かす需要があったんで、ちょっとDockerfileを作って整理整頓する。

これ。


nginx-luajit-ws

https://github.com/sassembla/nginx-luajit-ws



Centos

この世のどこかで需要があるというCentos用。

https://github.com/sassembla/nginx-luajit-ws/blob/master/centos.dockerfile



Ubuntu

この世のどこかでやはり需要があるというUbuntu用。

https://github.com/sassembla/nginx-luajit-ws/blob/master/ubuntu.dockerfile



Lua-uuid -> nginx requestId

ついでに、lua-uuidの実装を捨てて、nginxのrequestIdを使うようになった。


まあuse caseとしては必ずマッチング記録とかにアクセスするフェーズがあるんで、適当なuuidでもよかったのだけれど。



わりかしスッキリした。式年遷宮感ある。



備考

cat << EOF > nginx.conf


server {


       listen 80;


       location / {


               try_files $uri $uri/ =404;


       }


}


EOF


みたいな書き方楽でいいな。

そのうち更新しよう。



wrote 2017/06/24 22:17:55

DOTweenのいろいろ


概要

いろいろ。情報足してく。


これ。

https://www.assetstore.unity3d.com/jp/#!/content/27676

時間ベースなんでキャンセルとか早回しとかそのへんがやりにくくてツレーな。

詳しい人に聞きたいな。

適当にこうしとけば逃げ場が作れるな~みたいな感じの情報をまとめておく。



サンプルはこちら

DoTweenTest

https://github.com/sassembla/DoTweenTest


DOTweenはもちろん入ってないので自分で入れて。



Sequence使お

基本的な指針として。

https://stackoverflow.com/questions/37214649/how-to-kill-current-running-dotween-sequence-in-unity3d



// Grab a free Sequence to use

Sequence mySequence = DOTween.Sequence();


// Add a movement tween at the beginning

mySequence.Append(transform.DOMoveX(45, 1));


mySequence.Kill(); //Kill the sequence.



というかこれ以外の方法だとグローバル空間のDoTweenを使ってしまうような感じで、

他所のアニメーションの影響を受けて止まるとかがあるって聞いたんだけどマジ?

ここの記述は間違っていた。それぞれ独立したDOTweenを作る方法が別にある。

そのうち書き足す。



KillとCompleteの差

sequenceを使うことで、KillしたりCompleteしたことにしたりできる。いいね。

で、これらには差がある。


Killで終了させた場合、開始時に指定した完了時パラメータが調整されない。

Completeでは、開始時に指定した完了時地点をセットしてくれる。


サンプル作っといた。


KillDoesntFixPosition

https://github.com/sassembla/DoTweenTest/blob/master/Assets/TestCase/KillDoesntFixPosition.cs


CompleteDoesFixPosition

https://github.com/sassembla/DoTweenTest/blob/master/Assets/TestCase/CompleteDoesFixPosition.cs



最大でもN個まではエフェクト出すんだけどそれ以降出たら消す

というまあよくあるやつはこんな感じに書くと楽かもしれない。


CascadingEffectSample.cs

https://github.com/sassembla/DoTweenTest/blob/master/Assets/TestCase/CascadingEffectSample.cs



wrote 2017/06/23 18:08:30

Akeytsuでボーン+リギング 操作法


概要

操作ムービー見ててやっと手が慣れるところまで行ったのでホイホイと。



概念

・ジョイント(ボーン)を追加することができる

・モデルに対してジョイントをセット(bind)することができる(Skinning)

・モデルに対してジョイントをbindするとバンクにBind Poseが生成される

・モデルに対して、ボーンの追従度をセットすることができる



ざっくりした操作方法

1.ジョイントを作る

2.ジョイントを選択状態にする -> モデルを選んでbindする


と、モデルに対してボーンがセットされ、ボーンを動かすとモデルが動くようになる。



1.新規にジョイントを作る

1.JOINT ウィンドウのCreateボタンを押し(or Jキーを押す)、画面のどこでもいいのでクリックすると、最初のボーンが作られる。

2.マウスを適当に動かした状態でクリックすると、先ほどのボーンと連続した新しいボーンが作られる。

これ以上ジョイントを作成したくない場合、JOINTウィンドウのCreateボタンを再度押す(or Jキーを押す)と、生成が止まる。

2.ジョイントを選択状態にする -> モデルを選んでbindする

操作追記中




制約(MUST)

・すべての頂点は最低でも一つのジョイントの影響下にあること

みたいな制約がある気がする。その制約を守らないと、頂点に振ってある荷重をゼロにすることができず、意図せず動いてしまう、みたいなことが起きる。



ボーン一般の前提の話(SHOULD)

1.外見が左右対称なら、ポリゴンの分割もまあ左右対称がまあデフォよね

2.モデルは1つにマージしてある or 階層構造になってるのがデフォっぽい


2に関しては別のモデルで検証してみようと思う。



リギング周りの操作方法

ジョイントの選択 + spaceキーでのマウス操作が起点になっている。


1.ジョイントをクリックして選択

2.spaceキーを押した状態だとアイコンが変化し、その状態で頂点を囲むようにドラッグで選択、


で、選択したモデルの頂点に対して、SKIN ATELIERウィンドウから、1で選択したジョイントに対する荷重をセットすることができる。



荷重って何

選択したジョイントに対して、選択した頂点がどのように追従するかを、他のジョイントと分け合う重さ。


例えば一つの頂点がジョイントA, Bという2つのジョイントの中間にある場合、Aが動いた時に8割くらいAに引っ張られて、2割くらいBに引っ張られる、というような分配ができるようになっている。


この性質のため、「どのポイントにも属していない頂点」みたいなものは存在せず、bindを行なった時点で「全ての頂点はなんらかのジョイントに関連づけられている」という感じになっている。


最初にすべての点をどこかのジョイントに荷重100%で帰属させとくと良さそう。


wrote 2017/06/18 22:28:34

VSCode + Unityだと起動も動作も軽量でいいよ


概要

みたいな話。特にMac上。


まあもんのすげー今更なんだけど。

いろいろメモっておかないと忘れることができないので忘れてもいいように書く。



VSCode + Unityの利点

以下のような利点がある。


・最低限の機能はある

・起動も動作も軽量

・一切の個人情報入力不要

・VSCodeの他のプラグインとの連携が豊富

・フォーマッタがVS準拠(MonoDevelopやXamarinみたいな不思議フォーマッタではない)



インストールとか

1.VSCodeをDL

2.UnityにVSCode Assetを入れる

3.Unityからコード開く設定をVSCodeにセット

4.VSCode Assetの設定でIntegrationにチェック入れる

5..netCore入れる

6.mono入れる

7.VSCodeにC#Integrationを入れる

8.UnityのProject上とかからコード開く


以上。


4から先はなんかVSCode上で色々やってねって言われるんで従っていればOK。

wrote 2017/06/18 1:19:31

Akeytsuでボーンを入れるよ


概要

色々ツールを眺めていてウンウンって言う感じで



ワイヤーフレームにするには

左下のボタンでShadingが調整できる。numpadでも切り替えられる。

1でデフォルトの自由視点、2~で軸固定の方向視点。



Akeytsu上でモデルの中心位置を調節するには

ビュー上での回転操作とかが可能なので、Akeytsu上でもfbx -> 位置合わせをすることでできた。が、まあ、他のツールでfbxとしてで読み込んで、左右対称は左右対称として処理したほうがよさそう。



パースペクティブカメラのリセット方法

わからん。

Fキーでフォーカスが効く場合と効かない場合があって、exportして回避する感じになった。



ボーンを入れる

Jointメニュー -> Create でボーンを入れていく。

ボーンとメッシュ頂点との連携はあとで行える。

メッシュは統合されてるほうがよさげ。ふむ。



続く。手元で紙にガンガン書いた資料がある。




wrote 2017/06/13 23:23:45

Oculus Medium 資料リンク


概要

まだ散逸してるところっぽいのでまとめておく。

いろいろ良くなって行ってて良い。



フォーラム

現在の最も情報が集まってるところ。

https://forums.oculus.com/community/categories/medium


Manual user guide

全体的なツールのガイド。ちょっと既に古いような。


フォーラムにpdfが置いてある。

https://forums.oculus.com/community/discussion/49283/oculus-medium-manual-user-guide



Export pipeline guide

exportについての設定とか注意点とか。


フォーラムにpdfが置いてある。

https://forums.oculus.com/community/discussion/52947/medium-export-pipeline-guide



wrote 2017/06/03 3:13:15

Mediumでのモデリングexportを試す会とあとチートシート


概要

これ使うと楽、がいっぱいあったのでまとめる。


Traditionalスタンプ

ヘラとかの形をしたスタンプで、主に粘土を削るのに使う。

幅が広い(めっちゃ速く振って粘土削ってもバリが出にくい)のがすごくいい。


画像貼り

画像を画面内に貼ることができる。


さらにそこから、

・画像の移動をモデルと紐づける

・サイズ、向きは自在に調整

・一時非表示/表示/削除


とかができるので、さすがって感じ。



カラーチャートとかももちろん貼れる。スポイトでカラー採れたりする?

-> 画像として貼れるんだけど、スポイトはできない。残念。

で、これ、カラーを持った素材を放り込むことはできるんだろうか。

カラーを持った素材を生成する、みたいなことはできそうな気がするんだけど。

なんらかリクエスト出してみよう。-> 出した。



レイヤーもっといっぱい欲しい。無限に欲しい。

これはまあそういう感じで。フォーラムによるといい感じになるという予定はあるらしい。



レイヤーのオーダリングが欲しい

順番入れ替えたい。まあそういう感じで。



パーツ単位を維持したexport

objでもfbxでも、Mediumのレイヤー単位でのパーツを保持している。

Unity上とかだとこんな風に表示される。

スクリーンショット 2017-06-03 3.04.01.png

レイヤー順に関しては、アルファベット順になってるっぽい。まあ順に依存することはあんまないと思うけど。

モデリングの時でも、階層構造は欲しいな~~。



ZBrushとかに持ち込んだ時にどうなるか

-> ポリゴン軽減の話をどっかにまとめて書こう。

・ZBrushで減らすには

ZBrushでfbx, objの形式でレイヤー構造は生きるのだろうか(死んでるとこしかみたことない)

・Sympolygonとかどうなの


ポリゴン数記録

モデリングにもちょいちょい手が加わって行ってるのでまあ記録までに。

・ポリゴン数

・サイズ

・感じ

あたりをメモろうと思う。今後は。



130万ポリゴン -> 

DBBCnfEUwAAicbH.jpg

fbx24Mくらいあって、なるほど重たい。ディテールはほぼ完璧に出てると思う。まあザラザラしてるな~みたいなところも含めて。

このあたりをどう出力できるか、というのが知りたいところ



12,000ポリゴン -> DBGYIs3UQAAMkY3.png

objで頂点カラー。わりと形状出せてるような。オートの割にはまともっぽい。



5,000ポリゴン DBPwrmjVoAQ9nDw.png

わーなんとなく雑にリダクションされてる感じが好き。指が残ってるのが奇跡っぽさある。


export時のモデル位置の基準

フォーラムに資料が上がっている。


Export pipeline guide

https://forums.oculus.com/community/discussion/52947/medium-export-pipeline-guide


で。これ曰く、

地面の十字が交わるポイントがexport後のモデルの原点になるよ

とのこと。なるほど!




wrote 2017/05/29 11:45:08

Oculus Mediumで、レイヤーの回転をデフォルト状態に合わせて、左右反転がズレなくする



概要

ちょっと悩んでたMediumのレイヤー移動問題に解を見つけた。


簡潔にいうと、

・Flipで左右反転してるはずなんだけど意図しないところに反転するのを解消する

という感じ



編集中にレイヤーに回転を加えた状態でFlipを行うと、意図しないところに出る

これがまあわかりにくい事象で、

1.まあ適当に指を作る。

2.png



2.並べて適当にリサイズ

3.png




3.手のひらを作る

sassembla_2017-05-26_08-49-46.png



とかやったあとに胴体+肩を作って、さっき作った手を持ってきて、、

sassembla_2017-05-26_09-00-53.png


手の位置を合わせてくっつけて、さて

sassembla_2017-05-26_09-02-42.png



handのレイヤーを選択、DuplicateしてFlip! 右手の位置に手が、、とおもいきや、そうはいかず。

sassembla_2017-05-26_09-03-15.png



これ、handのレイヤーを回転させているから発生する現象で、

handのレイヤー内ではX軸を中心にFlipがちゃんと発生している。


handのレイヤーは回転が加わっているため、点線の位置あたりにFlipの軸が存在するのだ。

sassembla_2017-05-26_09-03-152.png



で、このままだと左右対称の位置、右手の位置にhandを左右対称コピーして出すことができない。

自由な移動でなんとかすることも可能だけど、まあズレる。手でやったらズレるよなあまあ。


というわけで、handのレイヤーの回転をデフォルトの軸で上書きして、

duplicate -> Flipで右手が出るようにする。


まずは新規レイヤーを作成(Layer 54が新規レイヤー)

sassembla_2017-05-26_09-22-21.png


次にhandのレイヤーをduplicateし(Layer55)、54-55をMergeする。

sassembla_2017-05-26_09-22-44.png



この状態でFlipをかけると、新規レイヤー = デフォルトの無回転の状態でFlipが発生するため、

めっちゃいい感じに右手が完成する。

sassembla_2017-05-26_09-22-54.png



もっとなんか変わった事象が起こる時があって、そのへんは追い中。

wrote 2017/05/27 0:19:27

SHOTGUNについて


概要

いろんな制作現場でその名前を聞くんだけど、

なんなのかわからない、話聞く相手によって内容がコロコロ変わるのが気になって、

Unite2017でブースがあったので聞いてみた。


そんなSHOTGUN

http://area.autodesk.jp/product/shotgun/



SHOTGUNの基本情報

・ワークレビューができて

・データベースになる

・プロジェクト管理ツール

うん、これをどうしたら

・Mayaで作ったシーンをUnity上でまんま再現するツール

になるんだろう、というのが俺の疑問だった。



結論

で、よく使われている用途としては、データベース as 香盤だった。

PythonAPIがあるので、そこから各社使い手がいろいろやっている。


香盤って何?

http://bit.ly/2q4SqXA


-> 演者とかに対するスケジュール表みたいなもの。

この演者がこのタイミングでどうこうする、みたいな。


で、いろんな会社では、Autodesk製品 -> Shotgun -> プラグインでデータを他のプロダクトに渡す/操作する みたいなことをやっているみたいだ。


なので「公式には、SHOTGUNには特にUnity連携のような機能はない」「みんなだいたいPythonで頑張って書いてる」という結論ぽい。



面白かった。


wrote 2017/05/10 1:46:08

RustでUnityのプラグインをビルドする


概要

これです。

keijiro/UnityRustPlugin

https://github.com/keijiro/UnityRustPlugin



環境構築からやってみたいひとはこちら

http://qiita.com/skitoy4321/items/0bf6826f948720bed821


ビルド

cargo build でCargo.tomlに書かれてる依存性解決とビルドが可能。ようはいろいろDLしてくる。

で、ビルドして完成したものがそもそもdylibなので、そいつを.bundleにするとmacでも読めるようになる。やったぜ!


ひとつだけ欠点があり、ビルド時にdylibのキャッシュが効いてしまっているので、

target/deps/該当するdylib を消す、みたいなことをしてからビルドを行う必要がある。


wrote 2017/05/06 16:10:53

オレオレ言語の字句解析 for いろんなプラットフォームについて


概要

Scalaでパーサコンビネータ作った以外で、ちゃんと言語の字句解析を行なったことがないのでやってみている。

参考

bison/flex(yacc/lex)について

http://hp.vector.co.jp/authors/VA022047/linux/bison.html


flex man

http://dinosaur.compilertools.net/flex/manpage.html



道具と使用場所に関する分析

やるべきことは

1.字句解析機を出力する

2.使う


なのだけれど、実際に使われる環境はどんななんだろうか。字句解析が行われるのが確定している環境は、

Unity

・ブラウザ


という感じで、ようはライブラリにできると良さそう。


適当にDocker上のLinuxから吐く。最終的にブラウザで使うならwasmにすればよかろう。c to wasmはどっかあった気がする。

そうでなくてもLLVM関連で出力できそう。

Unity向けであればC#ILか、やはりライブラリを出力したいところ。これにはどういう手段があるだろうか。



パースするべきものの設定とflexの実行

こんな感じの.lファイルをつくる。内容はmanに書いてあったやつ。


%option noyywrap

/* scanner for a toy Pascal-like language */


%{

/* need this for the call to atof() below */

#include <math.h>

%}


digit             [0-9]

alpha             [A-Za-z_]*

alpha_num         ({alpha}|{digit})

/*

こういうコメントは存在できるのか。

*/

%%


{digit}+ {

printf( "An integer: %s (%d) ", yytext, atoi( yytext ) );

}


{digit}+"."{digit}* {

printf( "A float: %s (%g) ", yytext, atof( yytext ) );

}


if|then|begin|end|procedure|function {

printf( "A keyword: %s ", yytext );

}


{alpha} printf( "An identifier: %s ", yytext );


"+"|"-"|"*"|"/" printf( "An operator: %s ", yytext );


"{"[^} ]*"}" /* eat up one-line comments */


[ ]+ /* eat up whitespace */


. printf( "Unrecognized character: %s ", yytext );


%%


main( argc, argv )

int argc;

char **argv;

{

++argv, --argc; /* skip over program name */

if ( argc > 0 ) {

yyin = fopen( argv[0], "r" );

} else {

yyin = stdin;

}


yylex();

}


うん、まだ全然わかんないや。とりあえずmanのいうとおりに進める。



flex parsel.l

で、lex.yy.cというcコードが出力される。

gcc lex.yy.c

それをgccとかでコンパイル。Macで実行するとclangが使われる。

特に名前を指定してないので、コンパイル結果としてa.outファイルが出力される。


ここでまあ、%option noyywrap とかを.lファイルの行頭に書いておくと、flexさんがyywrap(n)というdefineを追加してくれる。


今はまず字句解析の結果だけが欲しいので、これで動かす。



どんなものがパースされてどうなるんだろう

で、manに書いてあったサンプルがpascal-likeとのことだったので、雑にhello world + アルファを食わせてみる。


hello.pas

program Hello;


begin

  writeln('Hello, world.');

  Sentinel =0.0;

end.


で、

./a.out hello.pas


とか動かすと、

An identifier: program

An identifier: Hello

Unrecognized character: ;

A keyword: begin

An identifier: writeln

Unrecognized character: (

Unrecognized character: '

An identifier: Hello

Unrecognized character: ,

An identifier: world

Unrecognized character: .

Unrecognized character: '

Unrecognized character: )

Unrecognized character: ;

An identifier: Sentinel

Unrecognized character: =

A float: 0.0 (0)

Unrecognized character: ;

A keyword: end

Unrecognized character: .

、、、うん、まあ、なんていうか、うん。なるほど。

pascal likeだからな。


ちょっと改良して構文と内容の関連性がわかった。

で、やりたいことを実装に移す。



Emit2501形式では、時間経過的な駆動のために必要なパラメータと、実際にメソッドを着火するための機構が連結してある。

実行系もサクッと作ってしまったので、まあ、なんというか汚い。

これを綺麗にしていく第一歩として、パーサを実装していろんな環境で使えるようにしてみよう、という感じ。


とりあえずだいたいの部分はlexで字句解析できるようになった。


やったぜ!

wrote 2017/05/03 11:31:49

無責任なデータ放流機(WolfboyDispatcher)作った


概要

これ

WolfboyDispatcher

https://github.com/sassembla/WolfboyDispatcher



何用?

次のような需要があった。

・ネットワークから取得したデータを扱う。データは、基底型を拡張してある型のインスタンスで、型を判別する方法も提供/自作されている。

・データを上流から下流のとあるクラスのインスタンスへと渡したい、のだが、その下流がどんな型を受け取れるかには興味がない

・上流から下流へとデータを流したいが、下流のインスタンスは持ちたくない

・下流では、特定の上流から特定のデータ型だけを受け取りたいが、特に上流のインスタンスとかは持ちたくない


これらの条件が重なったので、それを果たすためのものを作った。

出来上がってみたらこれ型を使ったオブザーバパターン的な何かだ。メッセージングみたいな。



制約

わざと持たせてある制約として、型で上流 -> 下流をセットしあえるようにしてある。


また、型でしか同一性を見ていないので、レシーバ用のクラスのインスタンスを複数作ってレシーバ登録すると、

最後にセットしたReceiverしか意味を為さない。


まあ無秩序にReceiver作られても困るだけだし。あるポイントから同じ型のインスタンスへと拡散させたい場合はその場所にインスタンスいっぱい作って撒いてくれ、っていう。



なのでこいつは、

上流の型 -> 下流の型 へのデータ放流機なわけだ。



名前の由来

データを流す機構ならこのうえなく胡散臭いやつがいいなと思った。

wrote 2017/04/10 0:12:18

EventSystemのExecutionOrderに勝つ


概要

ほら、ScriptのExecutionOrderってあるじゃない。

で、EventSystemのExecutionOrderを上回りたいんだけどよくわからなかったので、調べてみた。



前提知識

UnityのEventSystemは、ざっくり書くと次のような構造でイベントを処理している。


1.EventSystemのUpdateで毎フレーム処理を開始

2.InputModule系でInput系の入力(Input.GetMouseButtonUpとか)を解析

3.奥深くにあるExecuteEvents系を着火

4.処理をUnityEventの系統に変換し、対象となるオブジェクトのメソッドを実行


で、このEventSystemのUpdateが発生する順番が、暗黙でべらぼうに高速なのがわかったっていう話。



調べ方

EventSystemの中で、次のような、StandaloneInputModuleを拡張したクラスを作って、その実行順を上回れないかどうか試す。


public class MyInputModule : StandaloneInputModule {

        public override void Process () {

            Debug.Log("processing. count:" + Time.frameCount + " button:" + Input.GetMouseButtonUp(0));

            base.Process();

        }

 }


で、実際に上回るには、いろいろな方法で実行順をセットできるんだけど、

参考:

【Unity】コンポーネントのイベント実行順についてのTips

http://tsubakit1.hateblo.jp/entry/2017/02/05/003714


個人的な事情により、metadataを書き換える方法で臨んでみる。


まあこんなmetadataを持つようなMonoBehaviourを継承したインスタンスがあったとして、

fileFormatVersion: 2

guid: d539e8a5875684b56879dabc6b0f9847

timeCreated: 1491113951

licenseType: Pro

MonoImporter:

  serializedVersion: 2

  defaultReferences: []

  executionOrder: 0

  icon: {instanceID: 0}

  userData: 

  assetBundleName: 

  assetBundleVariant: 


このexecutionOrderのところをいじればいいわけで。簡単。



いじってみた

-10 x

-100 x

-999 x

-1000 o


-1000になったところで、EventSystemと同列の時間軸に並ぶ。

で、あとはGameObjectの生成順の話になるので、

EventSystemより高速にGameObjectを生成できれば勝てる。




wrote 2017/04/02 17:21:28

タップしたらイベントを下位に伝搬しつつ消えるボタンの作り方


概要

簡単にやる方法があったので書く。

リポジトリはこちら。


Raycaster

https://github.com/sassembla/Raycaster



需要とか説明とか

なんでもいいからどこか押したら消えるウィンドウ

(しかも押した時の動作は打ち消さないでほしいみたいな狂ったニーズがあるとき)

に使える。


こんなGUIがあったとして、

スクリーンショット 2017-03-22 22.41.16.png


一番手前のが今回の話の対象で、これもボタンになっていて、

・押す(touchEndとかUp)と消える

・もしも押した位置が下のボタンにも入っていれば、ボタンを押したことにする


というキツいニーズを持っているとしよう。


そんなんねーだろって思うんだけど、ある。

こういうGUIを作りたいケース。

スクリーンショット 2017-03-22 22.49.39.png


まあ、さっきまで控えめだった半透明ボタンが画面に覆いかぶさってる。

これは、

・手前の白いボタンをタップしたらボタンについてるイベントが着火

・それ以外のところ(半透明)をクリックしたら、消えつつ下のイベントが着火


みたいな感じで、ようは

「白いボタンを押してイベントを発生させる or それ以外の範囲を押すと半透明や白いボタンが消えつつ下のボタンを押したことにする」

というような、排他的な領域のタッチ取得 + イベント発生に使える。


半透明のやつが全透明だったらもっとわかりやすいかも。

スクリーンショット 2017-03-22 22.51.34.png

この、青い丸で四角く括られてる部位を触ると、白いボタンが消えてこの領域も消えて、下のボタンを押したことになる、みたいなのが理想ですと。



理想のイベント発生順

・半透明のところをクリックすると、半透明と白いボタンが消える

・もし消すときにタップした位置にボタンがあったら、それを発動させる



実装の情報

UnityでのuGUIは便利なもんで、

EventSystemを使っていてくれる場合は非常に簡単にタッチイベントを遮ったり偽造したりすることができる。


具体的には以下の方法を使う。


1.でかいボタンを作る(半透明のやつ)

2.ボタンに次のようなコードを貼る

using System.Collections.Generic;

using UnityEngine;

using UnityEngine.EventSystems;


public class RaycastPreventor : MonoBehaviour {


    public void CatchTap () {

        // ここで、発生したイベントはなんなんだろう。というのを型で判断できそう。今後見てみる。


        this.gameObject.SetActive(false);


        var tapPos = new Vector3();

        if (0 < Input.touchCount) {

            tapPos = Input.touches[0].position;

        } else {

            tapPos = Input.mousePosition;

        }

        

        // 新規のpointerイベントを生成する

        var newPointerEvent = new PointerEventData(EventSystem.current);

        

        // ここでの位置のセットが必須。

        newPointerEvent.position = tapPos;

        

        var objectsHit = new List<RaycastResult>();

        EventSystem.current.RaycastAll(newPointerEvent, objectsHit);


        foreach (var objectHit in objectsHit) {

            // 同種のイベントを受けられるやつだけを通す。

            if (!ExecuteEvents.CanHandleEvent<IPointerClickHandler>(objectHit.gameObject)) {

                continue;

            }


            // 最初の一つにだけ、イベントを送り込む。

            ExecuteEvents.Execute<IPointerClickHandler>(objectHit.gameObject, newPointerEvent, (handler, eventData) => handler.OnPointerClick((PointerEventData)eventData));


            //一件通ったらもう着火する必要がないので、逃げる。

            break;

        }

    }

}


3.ボタンのOnClickイベントのとこに、CatchTapメソッドを貼る。

スクリーンショット 2017-03-22 22.54.44.png


これで、実装自体は終わり。やってることの紹介は以下。


実装内容紹介

次のような動作になってる。


1.CatchTap着火

2.this.gameObject.SetActive(false); でこのオブジェクト自体を無効化

3.tapPosを取得して、pointerEventを新規作成したものの位置に適応し、同じ位置でのイベントを作成

4.EventSystem.current.RaycastAll(newPointerEvent, objectsHit); で、このイベントにヒットするオブジェクト一覧を取得

5.取得したオブジェクトに対して、該当するイベントを受けられるかどうかチェック

6.イベントを受けられる物体を見つけたら、最初の一つだけにイベントを着火して完


調べるのに苦労したんだけどうーーーむ、APIドキュメントにサンプルコードが少ないのがキツいのかなあ。

継承関係とかはそりゃまあAPIドキュメント見ればわかるんだけど、利用例が一切ないコードを型情報からつなぎ合わせたり

欲しい動きをしそうなメソッドを探すのが大変だった。


GraphicRaycasterを使って云々したりもできるので便利。





wrote 2017/03/22 22:17:00

イベントシステムをどっかからすげ替える話


概要

完全に私的な実験のメモなので後から読んでも誰にも何もわからんと思う。



現在のタッチと同じRaycasterでどんなターゲットが存在するかを検知する

BaseEventData Constructor


public BaseEventData(EventSystems.EventSystem eventSystem);

Description

Construct a BaseEventData tied to the passed EventSystem.



っつーことなので、これでBaseEventDataが生成できるのでは?


・イベントを生成する

・RaycastAllする


という流れで、位置によってはいけそうな気が。

-> いけた。同じ位置でイベントを発行できる。

で、どんな種類のイベントが発生したかを取得できるだろうか。



GraphicRaycasterを使う手

http://gamedev.stackexchange.com/questions/93592/graphics-raycaster-of-unity-how-does-it-work


よくわかってないが、これがやりたいことは特殊そう。



イベントトリガの話

https://docs.unity3d.com/ScriptReference/EventSystems.EventTrigger.html

EventTriggerを拡張したクラスを作ると、いろんなイベントを傍受することができる?

ぽい?


やってみよう。



uGUIのインスタンスを上から叩く的な。

http://qiita.com/tadokoro/items/e72d6eff5998cb00ab02


やっていることは、

・current.currentSelectedGameObject がヒットするタイミングで、どのgameObjectがどんなポイントでタップされたか、をみる

・そいつと同じクリックを発生させて、可能性を見る

というやつ。


なるほどな~という感じなんだけど、こいつはオブジェクトを見ているあたりに可能性がありそう。



2501の対stateMachineまわりで困っていたのが、

・特定のインスタンスについてるStateMachineが叩けない

というやつで、これをなんとかする必要がある。


具体的には、

・特定のインスタンスを収集する(事前辞書の作成、GOについてるスクリプトのインスタンスの自動収集

・再現系のイベントがインスタンスに対して実行された際、そのインスタンスに対してメソッド実行を送り込む

・するとstateMachineから再現できる

的な。


実行記録からインスタンス割り出しをして実行できるなら、そいつはめっちゃ効率がいい。

メソッド実行のさらに上が必要な場合、それらを取得することも可能だと、可能性が広がる。


という感じ。


uGUI以前のCubeとかに対しての対策

PhysicsRaycasterとかが使えそうな気がする。

-> カメラに対してつけると、cubeとかも全て EventSystem.current.IsPointerOverGameObject() に反応するようになる。


で、イベント獲得 -> currentがnullなら、それは3Dオブジェクト向けのイベントなので、physicsRaycasterでオブジェクト判定して、その

いちばん上を見つける、ということが可能になった。


スゲー野蛮。


これで、記録レイヤーでいうと、

・どの3DオブジェクトがXXXされたか、gameObject単位で取得できるようになった


という感じ。

XXXには、いろんなイベントが入る。

で、記録に関しては光明が見えてきた。



再現

どのイベントが出たかがわかったので、今度は再現時にそれをGOに対してぶつける必要が出てくる。

そういうことができるようなEmit2501形式を実現できればよさげ。


・同じフレームで実行されたコマンドは、なんか把握できるはず。

・(伝搬元のオブジェクトに対してイベントを発行する、とかができるとスゲーー面白い。)


、、、あーーーそういえば実行できましたね、、、うん、、、

ゲームオブジェクト + コンポーネントなので、 stateMachineが付いている場合、そのインスタンスがゲームオブジェクト + コンポーネント名で

保持できていれば、単純にインスタンス名 + OnClickで、発動時にOnClickが起こったことにできるのでは?

-> 理屈上はできる。すげーな。



ラスト、再現用のオブジェクトリストの取得

最後の前提、

ゲーム中に存在しているGUI対象のオブジェクトのリストを取得する。

・GameObjectでMonoBehaviourを持ってるもの

条件を集めて、全体から検索できるようにしよう。クッソ重くてもできる自信はある。根拠は忘れた。



PlayMakerが対応してるイベント一覧

https://hutonggames.fogbugz.com/?W128




https://docs.unity3d.com/jp/540/ScriptReference/EventSystems.BaseEventData.html

ふむ、usedがある。



取得できた!!

<b>eligibleForClick</b>: False クリック時 ~ 放すまでの間にtrueになる。mouseDown, mouseUpの瞬間



階層構造的には、

PointerInputModule -> StandaloneInputModule という順に継承していて、

PointerInputModuleにはm_pointerDataが入っている。


で、


この辞書へは、Process関数でデータが詰められるようになってる。

同じ処理を走らせられれば、どんなイベントが発生するかを追うことは可能。


で、とりあえず今調べたいのは、最速でこのデータを調べた場合、PointerEventDataのbefore-Process-afterの両方を手に入れることで、

どんなイベントが発生したのかを追えるのではないか、という感じ。


そのためには、Processの存在位置が問題になる。


BaseInputModuleでのProcessは、EventSystemから呼ばれてる。

で、そのタイミングは、


Updateだ。よし、設定順が高速なら勝てる。


選択肢が2つ、先回りと後追い + 次フレームの調達というのができそうなんだけど、うーん、、


1.先回り + 現地調達

が確実か。


素早くインスタンスを作る

・Updateで挟む、ということをする。



テスト

・起動時初期化でインスタンスを作る

・シーン起動時に作る

とかで、まずはやって見るか。


どのイベントが発生したかを知る

-> ぶっちゃけ手段がない。

過去直近で発生したイベントを全て経由するポイントとかがあれば、それを見るのがいいんだけど。

-> もっと簡単に、endOfFrame使えば挟めるな。


-> できた。

EndOfFrameと挟み込むことで、イベントの着火を検知できるようになった。

・オブジェクトの検知は1f遅れる(というかendより後、Updateより前で着火してる) -> なので、実際のイベントが発生したのは-1frameになる。



スキャン

対象のオブジェクトが見つかるまで、Rayを打つ、ということができる。

GUIの対象物だけは事前に?

というか

Findすればいいんだよな?ということに気づいた。

名前がわかっていればFindできる。


同じオブジェクトがいっぱいある場合はどうなんだろう。名前で判別がつかないのか。

なにか絶対的なもの = idなんだけど、位置とかもあるはず。

ヒエラルキー位置みたいなのとか。


BaseInputModuleがrequire EventSystemを持ってしまっているので、二重化問題が発生する。

ので、やはりBaseInputModuleから先を模倣しないといけない。EventSystemの模倣になる。


あとは、発生して欲しいイベントがなぜ発生しないのかを追えればいい感じ。

functorか~~なんか違った気がするんだけどな、これらしい。

Enterとかの経路を見てみよう。


対uGUI

click

functor:UnityEngine2.EventSystems.ExecuteEvents+EventFunction`1[UnityEngine.EventSystems.IPointerClickHandler]

UnityEngine.Debug:LogError(Object)

UnityEngine2.EventSystems.ExecuteEvents:Execute(GameObject, BaseEventData, EventFunction`1) (at Assets/UnityEngine.EventSystems/ExecuteEvents.cs:367)

UnityEngine2.EventSystems.StandaloneInputModule2:ProcessMousePress(MouseButtonEventData) (at Assets/UnityEngine.EventSystems/StandaloneInputModule.cs:547)

UnityEngine2.EventSystems.StandaloneInputModule2:ProcessMouseEvent(Int32) (at Assets/UnityEngine.EventSystems/StandaloneInputModule.cs:466)

UnityEngine2.EventSystems.StandaloneInputModule2:ProcessMouseEvent() (at Assets/UnityEngine.EventSystems/StandaloneInputModule.cs:450)

UnityEngine2.EventSystems.StandaloneInputModule2:Process() (at Assets/UnityEngine.EventSystems/StandaloneInputModule.cs:233)

UnityEngine.EventSystems.EventSystem:Update()


このあと対象のメソッドが呼ばれてる

IPointerClickHandler

UnityEngine.Debug:LogError(Object)

UnityEngine2.EventSystems.ExecuteEvents:Execute(IPointerClickHandler, BaseEventData) (at Assets/UnityEngine.EventSystems/ExecuteEvents.cs:275)

UnityEngine2.EventSystems.ExecuteEvents:Execute(GameObject, BaseEventData, EventFunction`1) (at Assets/UnityEngine.EventSystems/ExecuteEvents.cs:392)

UnityEngine2.EventSystems.StandaloneInputModule2:ProcessMousePress(MouseButtonEventData) (at Assets/UnityEngine.EventSystems/StandaloneInputModule.cs:547)

UnityEngine2.EventSystems.StandaloneInputModule2:ProcessMouseEvent(Int32) (at Assets/UnityEngine.EventSystems/StandaloneInputModule.cs:466)

UnityEngine2.EventSystems.StandaloneInputModule2:ProcessMouseEvent() (at Assets/UnityEngine.EventSystems/StandaloneInputModule.cs:450)

UnityEngine2.EventSystems.StandaloneInputModule2:Process() (at Assets/UnityEngine.EventSystems/StandaloneInputModule.cs:233)

UnityEngine.EventSystems.EventSystem:Update()



exit

functor:UnityEngine2.EventSystems.ExecuteEvents+EventFunction`1[UnityEngine.EventSystems.IPointerExitHandler]

UnityEngine.Debug:LogError(Object)

UnityEngine2.EventSystems.ExecuteEvents:Execute(GameObject, BaseEventData, EventFunction`1) (at Assets/UnityEngine.EventSystems/ExecuteEvents.cs:367)

UnityEngine2.EventSystems.BaseInputModule:HandlePointerExitAndEnter(PointerEventData, GameObject) (at Assets/UnityEngine.EventSystems/BaseInputModule.cs:190)

UnityEngine2.EventSystems.PointerInputModule:ProcessMove(PointerEventData) (at Assets/UnityEngine.EventSystems/PointerInputModule.cs:284)

UnityEngine2.EventSystems.StandaloneInputModule2:ProcessMouseEvent(Int32) (at Assets/UnityEngine.EventSystems/StandaloneInputModule.cs:467)

UnityEngine2.EventSystems.StandaloneInputModule2:ProcessMouseEvent() (at Assets/UnityEngine.EventSystems/StandaloneInputModule.cs:450)

UnityEngine2.EventSystems.StandaloneInputModule2:Process() (at Assets/UnityEngine.EventSystems/StandaloneInputModule.cs:233)

UnityEngine.EventSystems.EventSystem:Update()


このあと対象のメソッドが呼ばれてる

IPointerExitHandler

UnityEngine.Debug:LogError(Object)

UnityEngine2.EventSystems.ExecuteEvents:Execute(IPointerExitHandler, BaseEventData) (at Assets/UnityEngine.EventSystems/ExecuteEvents.cs:257)

UnityEngine2.EventSystems.ExecuteEvents:Execute(GameObject, BaseEventData, EventFunction`1) (at Assets/UnityEngine.EventSystems/ExecuteEvents.cs:392)

UnityEngine2.EventSystems.BaseInputModule:HandlePointerExitAndEnter(PointerEventData, GameObject) (at Assets/UnityEngine.EventSystems/BaseInputModule.cs:190)

UnityEngine2.EventSystems.PointerInputModule:ProcessMove(PointerEventData) (at Assets/UnityEngine.EventSystems/PointerInputModule.cs:284)

UnityEngine2.EventSystems.StandaloneInputModule2:ProcessMouseEvent(Int32) (at Assets/UnityEngine.EventSystems/StandaloneInputModule.cs:467)

UnityEngine2.EventSystems.StandaloneInputModule2:ProcessMouseEvent() (at Assets/UnityEngine.EventSystems/StandaloneInputModule.cs:450)

UnityEngine2.EventSystems.StandaloneInputModule2:Process() (at Assets/UnityEngine.EventSystems/StandaloneInputModule.cs:233)

UnityEngine.EventSystems.EventSystem:Update()




対オブジェクト

enter

functor:UnityEngine2.EventSystems.ExecuteEvents+EventFunction`1[UnityEngine.EventSystems.IPointerEnterHandler]

UnityEngine.Debug:LogError(Object)

UnityEngine2.EventSystems.ExecuteEvents:Execute(GameObject, BaseEventData, EventFunction`1) (at Assets/UnityEngine.EventSystems/ExecuteEvents.cs:367)

UnityEngine2.EventSystems.BaseInputModule:HandlePointerExitAndEnter(PointerEventData, GameObject) (at Assets/UnityEngine.EventSystems/BaseInputModule.cs:222)

UnityEngine2.EventSystems.PointerInputModule:ProcessMove(PointerEventData) (at Assets/UnityEngine.EventSystems/PointerInputModule.cs:284)

UnityEngine2.EventSystems.StandaloneInputModule2:ProcessMouseEvent(Int32) (at Assets/UnityEngine.EventSystems/StandaloneInputModule.cs:467)

UnityEngine2.EventSystems.StandaloneInputModule2:ProcessMouseEvent() (at Assets/UnityEngine.EventSystems/StandaloneInputModule.cs:450)

UnityEngine2.EventSystems.StandaloneInputModule2:Process() (at Assets/UnityEngine.EventSystems/StandaloneInputModule.cs:233)

UnityEngine.EventSystems.EventSystem:Update()


exit

functor:UnityEngine2.EventSystems.ExecuteEvents+EventFunction`1[UnityEngine.EventSystems.IPointerExitHandler]

UnityEngine.Debug:LogError(Object)

UnityEngine2.EventSystems.ExecuteEvents:Execute(GameObject, BaseEventData, EventFunction`1) (at Assets/UnityEngine.EventSystems/ExecuteEvents.cs:367)

UnityEngine2.EventSystems.BaseInputModule:HandlePointerExitAndEnter(PointerEventData, GameObject) (at Assets/UnityEngine.EventSystems/BaseInputModule.cs:190)

UnityEngine2.EventSystems.PointerInputModule:ProcessMove(PointerEventData) (at Assets/UnityEngine.EventSystems/PointerInputModule.cs:284)

UnityEngine2.EventSystems.StandaloneInputModule2:ProcessMouseEvent(Int32) (at Assets/UnityEngine.EventSystems/StandaloneInputModule.cs:467)

UnityEngine2.EventSystems.StandaloneInputModule2:ProcessMouseEvent() (at Assets/UnityEngine.EventSystems/StandaloneInputModule.cs:450)

UnityEngine2.EventSystems.StandaloneInputModule2:Process() (at Assets/UnityEngine.EventSystems/StandaloneInputModule.cs:233)

UnityEngine.EventSystems.EventSystem:Update()



ProcessMove経由で、HandlePointerExitAndEnterが呼ばれている気がする。

その場所でnullになったり、GOになったりしてる?

pointerEvent.pointerCurrentRaycast.gameObject

にnullが入ってる。


なるほど。



PointerEventDataをoverrideしてると、pointerCurrentRaycast にraycastのsetが行われない、みたいだ。どこで実行されてるか調べたいんだけどな~~。参照を追うしかないか。



ただしいfrom-toは、


みほん CopyFromTo to.pointerCurrentRaycast:Name: Button (UnityEngine.GameObject)

module: Name: Canvas (UnityEngine.GameObject)

eventCamera: 

sortOrderPriority: 0

renderOrderPriority: 0

distance: 0

index: 0

depth: 0

worldNormal: (0.0, 0.0, 0.0)

worldPosition: (0.0, 0.0, 0.0)

screenPosition: (321.9, 129.3)

module.sortOrderPriority: 0

module.renderOrderPriority: 0

sortingLayer: 0

sortingOrder: 0


 vs from.pointerCurrentRaycast:Name: Button (UnityEngine.GameObject)

module: Name: Canvas (UnityEngine.GameObject)

eventCamera: 

sortOrderPriority: 0

renderOrderPriority: 0

distance: 0

index: 0

depth: 0

worldNormal: (0.0, 0.0, 0.0)

worldPosition: (0.0, 0.0, 0.0)

screenPosition: (321.9, 129.3)

module.sortOrderPriority: 0

module.renderOrderPriority: 0

sortingLayer: 0

sortingOrder: 0

UnityEngine.Debug:LogError(Object)

UnityEngine2.EventSystems.PointerInputModule:CopyFromTo(PointerEventData, PointerEventData) (at Assets/UnityEngine.EventSystems/PointerInputModule.cs:207)

UnityEngine2.EventSystems.PointerInputModule:GetMousePointerEventData(Int32) (at Assets/UnityEngine.EventSystems/PointerInputModule.cs:268)

UnityEngine2.EventSystems.StandaloneInputModule2:ProcessMouseEvent(Int32) (at Assets/UnityEngine.EventSystems/StandaloneInputModule.cs:460)

UnityEngine2.EventSystems.StandaloneInputModule2:ProcessMouseEvent() (at Assets/UnityEngine.EventSystems/StandaloneInputModule.cs:450)

UnityEngine2.EventSystems.StandaloneInputModule2:Process() (at Assets/UnityEngine.EventSystems/StandaloneInputModule.cs:233)

UnityEngine.EventSystems.EventSystem:Update()

これに対して、現在は

CopyFromTo to.pointerCurrentRaycast: vs from.pointerCurrentRaycast:

UnityEngine.Debug:LogError(Object)

UnityEngine2.EventSystems.PointerInputModule:CopyFromTo(PointerEventData, PointerEventData) (at Assets/UnityEngine.EventSystems/PointerInputModule.cs:209)

UnityEngine2.EventSystems.PointerInputModule:GetMousePointerEventData(Int32) (at Assets/UnityEngine.EventSystems/PointerInputModule.cs:271)

UnityEngine2.EventSystems.StandaloneInputModule2:ProcessMouseEvent(Int32) (at Assets/UnityEngine.EventSystems/StandaloneInputModule.cs:466)

UnityEngine2.EventSystems.StandaloneInputModule2:ProcessMouseEvent() (at Assets/UnityEngine.EventSystems/StandaloneInputModule.cs:455)

UnityEngine2.EventSystems.StandaloneInputModule2:Process() (at Assets/UnityEngine.EventSystems/StandaloneInputModule.cs:234)

UnityEngine2.EventSystems.EventSystem:Update() (at Assets/UnityEngine.EventSystems/EventSystem.cs:351)



両方ともnull。ふーむ。


-> 自分で作った方は該当するRayCasterがなかった。ので、作ればいけそう。

BaseRaycaster -> GraphinsRaycasterと、PhysicsRaycasterの2つ、、




選択肢は2つあって、

1.Raycasterを自作して追加する

2.RaycastManagerをハックしてリストを取得する


たぶん1のほうがいい。


uGUIに関してはできた。

で、あとは


・GameObjectへのタッチがまだ取れてない -> できた

・uGUIへのイベントの深度がちょっと違う


IPointerEnterHandler

UnityEngine.Debug:LogError(Object)

UnityEngine2.EventSystems.ExecuteEvents:Execute(IPointerEnterHandler, BaseEventData) (at Assets/UnityEngine.EventSystems/ExecuteEvents.cs:251)

UnityEngine2.EventSystems.ExecuteEvents:Execute(GameObject, BaseEventData, EventFunction`1) (at Assets/UnityEngine.EventSystems/ExecuteEvents.cs:392)

UnityEngine2.EventSystems.BaseInputModule:HandlePointerExitAndEnter(PointerEventData, GameObject) (at Assets/UnityEngine.EventSystems/BaseInputModule.cs:231)

UnityEngine2.EventSystems.PointerInputModule:ProcessMove(PointerEventData) (at Assets/UnityEngine.EventSystems/PointerInputModule.cs:301)

UnityEngine2.EventSystems.StandaloneInputModule2:ProcessMouseEvent(Int32) (at Assets/UnityEngine.EventSystems/StandaloneInputModule.cs:468)

UnityEngine2.EventSystems.StandaloneInputModule2:ProcessMouseEvent() (at Assets/UnityEngine.EventSystems/StandaloneInputModule.cs:450)

UnityEngine2.EventSystems.StandaloneInputModule2:Process() (at Assets/UnityEngine.EventSystems/StandaloneInputModule.cs:233)

UnityEngine.EventSystems.EventSystem:Update()

ここまで来る必要がある。



できた~~~



で、Dragとかも補足はできたので、あとはClickのイベント発生の中身を追うとかすると良さげ。

-> 特に同じオブジェクト判定とかしてないっぽいな、、なんか制約があると思ったんだけど。


uGUIの検知が1f遅れる?

なんか初期化順の問題なのかな


my processのほうが実行が早いのに、判定は遅れる。

これはバグっぽい。よくない。


IPointerClickHandler:88

UnityEngine.Debug:LogWarning(Object)

UnityEngine2.EventSystems.ExecuteEvents:Execute(IPointerClickHandler, BaseEventData) (at Assets/UnityEngine.EventSystems/ExecuteEvents.cs:276)

UnityEngine2.EventSystems.ExecuteEvents:Execute(GameObject, BaseEventData, EventFunction`1) (at Assets/UnityEngine.EventSystems/ExecuteEvents.cs:401)


UnityEngine2.EventSystems.StandaloneInputModule2:ProcessMousePress(MouseButtonEventData) (at Assets/UnityEngine.EventSystems/StandaloneInputModule.cs:556)

UnityEngine2.EventSystems.StandaloneInputModule2:ProcessMouseEvent(Int32) (at Assets/UnityEngine.EventSystems/StandaloneInputModule.cs:475)

UnityEngine2.EventSystems.StandaloneInputModule2:ProcessMouseEvent() (at Assets/UnityEngine.EventSystems/StandaloneInputModule.cs:456)

UnityEngine2.EventSystems.StandaloneInputModule2:Process() (at Assets/UnityEngine.EventSystems/StandaloneInputModule.cs:235)

UnityEngine2.EventSystems.EventSystem:Update() (at Assets/UnityEngine.EventSystems/EventSystem.cs:350)


この判定がもう一歩高速でないとおかしい。Updateか。



Processで、ProcessMousePressまではきてる。

で、ここからの挙動に差がある。

ReleasedThisFrame

なるほど、Update時にはtrueになってないんだ。ということは、

・Update

・何か

・EventSystemが処理する

という順で動いている?それも妙な話だな。



processing. count:1208 button:True

UnityEngine.Debug:LogError(Object)

MyInputModule:Process() (at Assets/MyInputModule.cs:14)

UnityEngine.EventSystems.EventSystem:Update()


この中に、Input.GetMouseButtonUpをtrueにしている要素があるはず。

ってなるとInputなんだけどねえ。



思い違いをしていた。

eventSystemは、endOfFrameよりあと、次のUpdateより前で動いている。

つまりeventSystemの使っているUpdateがすごく特殊。


-> 組み込みのExecutionOrderがあるみたい。なので、次の結論が得られた。


・EventSystemが既に存在する場合のみ、順に配慮した動きが必要になる

・5.5以上でないと多分追い抜けない(それでも追い抜けないかもしれない

-> tapでインスタンスがnullにされたりすると、事後でしか追いつけないので、記録が同じにならない可能性がある

-> 直前のフレームに処理を差し込むにはEventSystemに乗っかるか、先に実行するしかない。乗っかる方は辛いのでやりたくない。


・eventSystemが存在しなければ特に問題なさげ?

-> 腕力でexecutionOrderいじりたい

-> metadata編集で勝てた。-1000つよい。

-10 x

-100 x

-999 x

-1000 o


イェーイ。

ということで、運用するなら、metadataを開けてなんとかする機構が必要になる。

そしてこの機構のために、この部分だけをコードで用意する必要がある。


なるほど。












wrote 2017/03/22 21:33:54

SAOのしおり


概要

SushiArtOnsenの略。



旅程

新宿 -> 小田原 -> -> コロナ温泉 -> コロナSAO -> 小田原 -> 新宿


集合場所

新宿駅小田急線乗り場に9時 ~ 9時20分くらいまでに集合してるといいと思った。


ターゲットとなる列車はこれ。

はこね11号 9:30 新宿発、10:36 小田原着。

スクリーンショット 2017-03-10 15.15.07.png



ぶっちゃけ10:30くらいに到着できれば平和そのものだと思うので、そのあたりに到着するのでこれで。


スケジュール

~ 9:20 

集合。


9:30

ロマンス発進


10:36

小田原


11:00

禅開店


1X:XX

小田原コロナワールドへ移動

1X:XX

温泉


19:00

SAO上映開始


21:10

SAO上映終了


2X:XX

帰路



当日の移動手段

新宿駅 -> 小田原駅

ロマンスカー。購入済み。

スクリーンショット 2017-03-10 15.19.57.png


->

タクシー。


-> コロナ温泉 -> コロナSAO -> 小田原駅

タクシー。


-> 新宿駅

何か。



wrote 2017/03/12 00:00:00

Unity5.6で非同期テストするときの基本的人権が保護されそう


概要

今はまだβなんだけど、Unity5.6には複数の機能が追加されそう。


・テストをPlay時に実行することができる

・IEnumeratorを返り値とする非同期なテストができる


という感じでいろいろ革新がある感じ。


これをディズニーランドの城ジェクションマッピング待ってる間に書いてる現在のverはβ11。

https://unity3d.com/jp/unity/beta



TestRunnerがPlayModeに対応

今までのモードはEditModeとしてそのままに、

PlayMode という「実行するとPlay開始し、完了するとPlay終了する」というテストモードが増えた。

スクリーンショット 2017-03-09 18.55.43.png


Enable playmode testsボタンを押すと、「エディタ再起動してね!」って言われるのがすごくbeta感ある。


再起動するとボタンは「テストを作成する」ボタンに変わるので、押すと雛形として「NewPlayModeTest.cs」がAssets/フォルダに直に吐かれる。



コード

こんな感じのコード。


using UnityEngine;

using UnityEngine.TestTools;

using NUnit.Framework;

using System.Collections;


public class NewPlayModeTest {


[Test]

public void NewPlayModeTestSimplePasses() {

// Use the Assert class to test conditions.

}


// A UnityTest behaves like a coroutine in PlayMode

// and allows you to yield null to skip a frame in EditMode

[UnityTest]

public IEnumerator NewPlayModeTestWithEnumeratorPasses() {

// Use the Assert class to test conditions.

// yield to skip a frame

yield return null;

}

}


Test attributeのほうはまあいつも通りのなんの面白みもないテストなんだけど、

UnityTest attributeの方が素晴らしくて。


・IEnumeratorを返すユニットテスト

・yieldを使ってテストの終了を遅延させることができる

= 非同期テストができる


という素晴らしい特性を獲得している。これが欲しかったのでMiyamasuとか作ってたんだけど。



例えば1000frame待つという簡単なテスト

こんな感じになる。

using UnityEngine;

using UnityEngine.TestTools;

using System.Collections;


public class NewPlayModeTest {


    int frame = 0;


    [UnityTest] public IEnumerator NewPlayModeTestWithEnumeratorPasses () {

        while (true) {

            if (frame == 1000) {

                Debug.Log("1000 frame passed.");

                break;

            }

            yield return null;

            frame++;

        }

    }

}


うーーーん簡単。ちゃんとPlayモードで動作する。



テスト完了時にチラッと見える「N件成功!」的なビューがあるんだけど

なんかじっくり見るにはどうすればいいんだろう。もうちょい調べる。



残る課題というかやりたいこと

実機で動かしたいので、なんらかランタイムのコードからこれらを着火する方法を見つけたい。


あと、実機でのテストの結果とかを集計したいねっていうのがこないだの春の自作Unityテストツール祭りで話題に出てたので、

そのへんも叶えたい。



wrote 2017/03/09 19:09:05

UnityCloudBuildEnterpriseというような物体


概要

ようはインターフェースとしてはCBのようなものが欲しいんだけど待ってらんないので

手元のマシンでああいう感じのやつを動かしたくないですか。

GithubEnterpriseみたいに。

あとDockerで。


まあ本家があの機能をDocker化してくれたら済むという部分がある感じは本当に否めない。

でも単に欲しいっていうのつまんないので作って有用性を知ってから見せたりしてみたい。



要件

CloudBuildのできることの中で、以下ができるようにしたい。


・UIからビルド

・githubからのwebHookを受けpullしてビルド

・iOS/Android/Mac/PC向けにビルド

・DLリンク出してDL、インストールが可能

・iOSのenterpriseビルド、その他の実機ビルド

・エディタ上Play時テストの着火と結果待ち


これらの要件から、Macでだけ動けばいいや、という感じになる。


また、追加で適当に欲しい機能として、

・実機でのPlay時テストの実施と結果の収集と開示

・実機での動作statsの収集と開示

がやりたい。




wrote 2017/03/08 18:49:28

Miyamasuを支える技術というかUnityEditorロックインな知識


概要

Miyamasuを作った時に発覚したいろんな新常識を列挙していく。


Miyamasu

https://github.com/sassembla/Miyamasu



PlayerのTheadとUnityEditor.EditorApplication.updateの話


Unityの制作環境には大きく2つ、MainThreadへのアクセスポイントがあり、

1つはPlayerが動いているときのUpdateとかあのへん。MonoBehaviourが動いているContext。


もう一つは、UnityEditor.EditorApplication.updateが動いているContext。



この2つのContextは、根本的には一つのThread(= MainThread)にアクセスしていて、その動作に差異は「ほぼ」ない。


具体例として、

UnityのMainThreadでしか動かないよ~的なメソッドは、そのほぼ全てが UnityEditor.EditorApplication.update でも動かすことができる。



Play中でないと絶対に動かない処理がある

UnityEditor.EditorApplication.update と、MonoBehaviourは等価っぽい、、、のだけれど、


次のメソッドは、Play中でないと動作が完了しないことがわかっている。

・LoadAssetAsync

・ConfigurationBuilder.Instance

LoadAssetAsync

DLしたAssetBundleを非同期で読み出す処理なんだけど、全然完了しない。


ConfigurationBuilder.Instance

課金機構の設定用のインスタンスを返す処理なんだけど、これまた全然完了しない。


これらは、UnityEditorがIsPlaying = trueでないと動作しない。

が、


裏を返せば、UnityEditorがIsPlaying = true でさえあれば、

例えば、UnityEditor.EditorApplication.updateからでも動作する。


考察としては、

・これらのメソッド中には、Play中かどうかをみて動くような処理が実装されている

という感じ。


もしくはバグ。だってUnityWebRequestとか同期版のLoadAssetは動く。

この2つのメソッド以外にもあるかも。(特に探せてない


ちなみに実機上でテストを動かす場合には全然問題ない。



なぜNUnitを使わないかについて、、、うん、、、、

Unity、NUnitを使ってテストを書くことができるんだけど、テスト実行単位で一つのMainThreadだけが動く状態で、

MainThread主体のコンテキストで動いてしまい、MainThreadを空転させるような動作ができない。


もうちょっというと、例えばStartCoroutineして、その処理の終了を待つ、みたいなことができない。


MainThreadで動いてて、MainThreadで動かすような処理を待ちたい、で、待つ = ロックしちゃう = 非同期で完了を待ちたい処理もロックしちゃう。


ので、非同期的な処理を待つことができない。


ので、非同期テストができない。


ご丁寧なことに、NUnit中には、上記のUnityEditor.updateも動かない。

はい解散。




wrote 2017/03/04 9:29:27

Mangalooふむふむ


概要

Mangaloo、これ。

https://www.mangaloo.jp/



wrote 2017/03/01 19:08:19

Unity 5.5.1でIAPを含んだプロジェクトが面白いくらいCPUを食う問題について


概要

やあ、全国のUnity5.5.1のCPU使用率が100%を超えるみんな。

問題とその解決策を見つけたのでちょっと書いた。



Unity 5.5.0 -> 5.5.1へと移行したら、CPU使用率がウケル感じになる

スクリーンショット 2017-02-22 20.06.51.png

こんな感じに。


症状としては、

・IAPの利用コードがあるプロジェクトをPlayをすると、UnityのCPU使用率がすっげーアガる

・Playを停めても上がったまま

・Unity再起動すると治るが、Playを押すとまた発生する


というもの。


と言っても問題なのはプロジェクトではなく、プロジェクトに含まれている

Unity IAPのライブラリのバージョン だった。



古いバージョンのUnity IAPライブラリが含まれているプロジェクトを新しいUnity EditorでPlayするとCPUが青天井になる

ということがわかった。


解消方法としては簡単で、

・Unity IAPのライブラリを更新する

という感じ。


具体的にいうと、

スクリーンショット 2017-02-22 16.39.53.png

Unity IAP is up to date 

って出るまでReimportボタンを押せばいいと思う。



問題点の切り分け

まず、あるコードを実行すると、CPUが跳ね上がっているという情報をもらった。環境はUnity5.5.1p4とのこと。

自分の方では手元に5.5.1p3があったので、まずp3で同じ事象が起こるかどうか試してみた。


・5.5.1p3であるプロジェクトをPlay、確かにCPU使用率がいい感じに跳ね上がるのを確認した。

・同じプロジェクトを5.5.0p4でチェックすると、CPU使用率は跳ね上がらなかった。

・そのプロジェクトは5.5.0p4での生成時に取得していたIAPのdllを含んでいた。

・5.5.1p3で動作時、どの処理があったらCPUが跳ね上がるのか確認していくと、IAPの関数を実行した時点からCPUが上がって行くのが確認できた。


という感じ。



実際にCPU持って行く箇所はどこなのか

実際にCPUを持っていくのは、UnityEditor上でPlayを押した際、StoreのアイテムIdとかを設定する処理を行う部分。

UnityPurchasing.Initialize 関数の中。


一度Playすると、たとえ停止をしてもそのCPUのアガりっぷりは衰えない。

なにこれこわい。


該当の UnityPurchasing.Initialize 関数自体を実行しなくなると、CPUが跳ね上がる問題は消える。

まあ課金処理ができなくなるんですけど。


Unity IAP、自分自身ではバージョンが古いからアップデートしてね!みたいなこと一切言わないのだけれど、

もしかしてな~~って思ってServicesのIN-APP-PURCHASING の項を見に行ったら、更新できるよっていう感じだったので

二度ほど押せて、二度コンパイルが走ったあとで治った。



今後の対処方

こういうのなんか、、難しいね、、、

実行コード上からは、IAPライブラリのバージョンを気にするようなことはないので、エラーの原因に気づけない。

UnityのServicesのUIを見に行ってやっと気づく。というかそこを見ても原因かどうかは気づけない。

試して「あっ治った」っていう状態があるのが、まあ、今の俺、という程度。



UnityEditorのバージョンと、配布されてたIAPのライブラリの食い合わせ問題みたいなのがあるんだろうか。

このエディタだったらこのバージョン以上のIAPライブラリ使ってなかったらWarning みたいなのは作れるかもしれないな。


UnityのIAPのライブラリ、痒いところに手が届く素晴らしいバランス(運用スタイルによるがAndroidとかの堅牢性を信じてない人であれば全く問題ない設計)なので

極力使用したい。



追記

他にも原因となる要素があるっぽい。

自分の場合はこれだった、、のか?よくわかってないが出てない。

続報が出せたら書く。

wrote 2017/02/22 19:57:47

SuekkoっていうC#スクリプト -> Unity GUI Windowなツール作った


概要

いちいちUnity specificなコード書くのめんどいので、

単に型を指定すると、そのパラメータをGUIにしたり、インスタンスのメソッドを実行できる、というやつを作った。

Suekko

https://github.com/sassembla/Suekko



内容

こんな感じのコードが、

スクリーンショット 2017-02-12 23.53.26.png



Suekkoクラスに上記の型を1つ書くだけで、自動的にこんな感じのGUIになる。

メソッドも抽出されてて、GUIから実行できる。

スクリーンショット 2017-02-12 23.53.06.png


まだこのウィンドウを作り出すコード自体への型の指定部分が納得いってない。


現在プロトタイプという感じなので、できればコンソール(そのクラス内でなんか実行した時に出たログをウィンドウ上に出す)みたいなのをやりたい。

wrote 2017/02/13 0:00:35

Unity 春の自作テストツール祭り


概要

Unityのテスト、みんなどうしてる?

NUnitでUnityのMonoBehaviourのUpdateとかが関係ない領域でユニットテストだけ書いてる?

それとも旧来のIntegratedツールを使ってる?

それとも、、自作してる?


自作してるよね?


勝手に作った自動化ツールとか、勝手に作った非同期テストのための仕掛けとか、あるよね?

あるよね?!!?


そういうののノウハウで殴り合う会をしてみたいと思う。



場所

渋谷駅の近所。徒歩5分くらい。

人数いっぱい増えたらDotsとかにしたいけどさてはて。



日時

2017/03/04 (Sat)


募集要項

なんらかUnityでゲーム作るときにテストツール自作したことがある人

その苦労話をしたい人

輝かしい成果を誇りたい人

俺のツールを聞けーー!! って言いたい人

またはそのへんをこれからまさに作ろうとしている人

ツールの必要性を感じている(今困っている)人


などが来るといいと思ってます。


上限人数

条件的に20人くらいが限界かな~と思っている。

わりと急だし。俺のせいで。


もっとも、興味ある人の人口もそんなにいないんじゃないかとも思っているんだけど。



質問とかその辺

@toru_inoue まで。フォローとかしてなくてもDM送りつけることができるぞ。

wrote 2017/02/11 13:03:01

Caching.IsVersionCached(url, hash) ってどういう挙動?


概要

Caching.IsVersionCached(url, hash) の挙動がよくわからない。

ドキュメントにも書いてないし。

https://docs.unity3d.com/jp/current/ScriptReference/Caching.IsVersionCached.html


でも実装はされてて、Unity5.5p4とかだと使える。(もっと前から使える。)


で、この関数のどんな挙動が悩ましいのか、書いていく。



hashを使ったAssetBundleのDLについて


5.x系だと、こんな感じのメソッドを使ってAssetBundleをDLできるようになってる。

public static Networking.UnityWebRequest GetAssetBundle(string uri, Hash128 hash, uint crc);


ドキュメントはこれ。

https://docs.unity3d.com/ScriptReference/Networking.UnityWebRequest.GetAssetBundle.html


とあるurlに紐づいてDLされているAssetBundleについて、このメソッドに渡したhash値がDL時のhash値と一致しなかったら、DLが発生する。

そうでない場合はAssetBundleがストレージにキャッシュされてるので、そこから取得する、みたいな。


で、だ。この関数には良いところがいっぱいあって。


・キャッシュに含まれていたら + hashが合致していたら、AssetBundleが取得できる

・キャッシュに含まれていなかったらAssetBundleをDL、取得できる

・キャッシュに含まれていなかったらAssetBundleをDL、キャッシュもする

・キャッシュに含まれていたら + hash合致しなかったら、やはり取得しに行く

キャッシュに含まれていたら + hash合致しなかった場合、古いファイルは消える(消えますよね? 消えますよね?? 明文化されてない気がするけど!!

・crcで正しいファイルかチェックできる


などなど。hashが本当にいい仕事してる。versionのようなヘタレとは違うのだ。違うのだ。


で、次は、「AssetBundleむかしDLした気がするんだけど、このAssetBundleってあるんですか?」って確認したいだけの場合。

まあ、、、この機会を「実際に使用しないならいいじゃん!実際に使用するときはRequest使えばいいじゃん!」みたいな話で没シュートしたい場合、

かつ、そのためCaching.IsVersionCached(url, hash)がドキュメントに書いてないという事情な場合、話はシンプルにまとまりそう。


hashを使ったAssetBundleがキャッシュされているかどうかのチェックについて

本題。

ざっくりいうと、hashを使ったIsVersionCheckedは、どんなhashを渡してもtrueが返ってくるときがあるようだ。

サンプルを用意した。

wrote 2017/02/10 13:56:21

Autoyaのドキュメント


概要

書く。

Autoya

https://github.com/sassembla/Autoya



Unityを使って5秒で認証付きゲームを作り始められるようにするためのフレームワーク。

いろんな機能が入ってるが、それらを使うための準備にかかる時間が限りなく短い、というのを目指している。


ぶっちゃけ何の設定変更もせずに、プレイヤーのidentityを持たせた状態でゲーム開始ができる。



基礎的な構造

Autoyaという名前のstatic instanceをインターフェースとした、いろいろな便利機能の集合体になっている。


コアとなるのはAuthentication(認証)処理で、ゲーム起動時に勝手に認証処理をバックグラウンドで開始、

認証完了したら、その認証情報を入れた通信などが可能になる。



依存の図

Backyardフォルダにある機能がAutoyaとしての処理を行うコードがある場所になっており、

Backyard以外のフォルダの機能はそれぞれ単体で使用することができる。


スクリーンショット 2017-01-27 5.23.45.png


例えば、「認証処理なしで、適当な外部サービスと通信をしたい」という場合には、Connections/HTTPをAutoya経由でなく勝手にnewして使えばいいし、

課金処理だけを使いたい、という場合はPurchase/PurchaseRouterだけを持ち出せばいい、という感じに使える。


便利なアクセッサとしてのAutoya

AutoyaのBackyardが提供する機能は、すべて

Autoya.(ドット)


と書き始めることで、ゲーム中のどのような場所からでも使用できるようになっている。


こんな感じに補完候補が出る。


scr.png



ここで使用できる機能は、通信系であればもれなく認証がついた状態で行われる。

課金処理なども同様に、通信に関しては全て認証がついたりする。



カスタマイザブル

認証処理やメンテナンスの検知など、Backyardが提供する機能は、Autoya/Backyard/OverridePoint.cs というファイルを更新することで挙動の内容を変更することができる。

特定のタイミングで着火されるハンドラを提供していて、認証フローの要所要所での保存内容やバリデーションや暗号化、サーバがメンテになってる時はこんなコードを返す、

というようなカスタマイズができるようになっている。


抜粋するとこんな感じ。


OverridePoints.cs

/**

    modify this class for your app's authentication, purchase dataflow.

*/

namespace AutoyaFramework {


    public partial class Autoya {

        /**

            return if server is under maintenance or not.

        */

        private bool IsUnderMaintenance (int httpCode, Dictionary<string, string> responseHeader) {

            return httpCode == BackyardSettings.MAINTENANCE_CODE; // どんなhttp response code / response header が来たらメンテナンス画面を出すか

        }


        /**

            return true if already authenticated, return false if not.

            you can load your authenticated data (kind of Token) here.

        */

        private bool IsFirstBoot () {// どんな条件だったら、初回起動と見なすか

            var tokenCandidatePaths = _autoyaFilePersistence.FileNamesInDomain(AuthSettings.AUTH_STORED_FRAMEWORK_DOMAIN);

            var isFirstBoot = tokenCandidatePaths.Length == 0;

            if (!isFirstBoot) {

                // load saved data and hold it for after use.

                return false;

            }

            return true;

        }


        /**

            send authentication data to server at first boot.

        */

        private IEnumerator OnBootAuthRequest (Action<Dictionary<string, string>, string> setHeaderAndDataToRequest) {// 初回起動リクエスト時、サーバに何をどんな風に送るか

            // set boot body data for Http.Post to server.(if empty, this framework use Http.Get for sending data to server.)

            var data = "some boot data";


            // set boot authentication header.

            var bootKey = AuthSettings.AUTH_BOOT;

            var base64Str = Base64.FromBytes(bootKey);


            var bootRequestHeader = new Dictionary<string, string> {

                {"Authorization", base64Str}

            };


            setHeaderAndDataToRequest(bootRequestHeader, data);

            yield break;

        }


        /**

            received first boot authentication result.

            if failed to validate response, call bootAuthFailed(int errorCode, string reason).

                this bootAuthFailed method raises the notification against Autoya.Auth_SetOnBootAuthFailed() handler.

        */

        private IEnumerator OnBootAuthResponse (Dictionary<string, string> responseHeader, string data, Action<int, string> bootAuthFailed) {

            var isValidResponse = true;// 初回起動レスポンスを受け取った時、どんなチェックをおこなって正しかったらどうするか(ファイルを保存する、どこかに通信する、 etc、、

            if (isValidResponse) {

                Autoya.Persist_Update(AuthSettings.AUTH_STORED_FRAMEWORK_DOMAIN, AuthSettings.AUTH_STORED_TOKEN_FILENAME, data);

            } else {

                bootAuthFailed(-1, "failed to boot validation.");

            }

            yield break;

        }


全体はこんな感じ。

https://github.com/sassembla/Autoya/blob/master/Assets/Autoya/Backyard/OverridePoints.cs



大まかな認証フローやそれに関連するハンドラは全てこのファイルに定義されていて、それらにどんなパラメータをどう暗号化して入れるか、などを自在にできるようにしてみた。



設定

const的な設定ファイルは、すべてAutoya/Settings フォルダ以下にある。

https://github.com/sassembla/Autoya/tree/master/Assets/Autoya/Settings



認証フロー

初回起動時のサーバへの通信と、それ以降のtokenを使った通信をサポートしている。

JWTなんかも入っているので、暗号化したりシグニチャ作ってサーバで検証したり、とかも楽に導入できる(楽にセキュアにうまくいくかどうかは知らない。



そのうち、全OverridePointsが対応するフロー図を書く。



URLs

Autoyaは、デフォルトのフローでは次のURLを要求する。


認証系

1.初回起動認証URL

2.TokenRefreshURL

課金系

1.アイテム一覧取得URL

2.購入事前処理URL

3.購入事後処理URL


AssetBundle系

1.AssetBundlesList取得URL

2.PreloadList取得URL

3.Asset取得URL


メンテナンス系

1.メンテ情報取得URL


基本的に、この9つのURLがあれば、Autoyaの要件にそったアプリケーションの運営ができる。

それぞれのURLについて明記しておく。



認証系

1.初回起動認証URL

初回起動時にAutoyaからゲームサーバへと送付される通信のURL。

Get or Postで、暗号化された情報をゲームサーバに送り、ゲームサーバ側でユーザー情報やシークレットなどを作成し、

クライアント側で保存すべきデータ(token、ほか)をレスポンスで送り返してくるのを想定している。


2.TokenRefreshURL

ゲームサーバは、クライアントが送付してきたtokenが失効していた場合、401などのレスポンスコードでクライアントに失効を伝えることができる。

この際、クライアントはTokenRefreshURLへとGet or Postでのtoken再発行処理の通信を行う。

ゲームサーバ側でtoken再発行処理がうまくいった場合、クライアント側で保存すべきデータ(token、ほか)をレスポンスでクライアントへと返すことを想定している。



課金系

1.アイテム一覧取得URL

アプリケーション起動時に、クライアントがこのURLにGetで通信する。

クライアントがこのURLに通信して来た際、ゲームサーバはこのプレイヤーが購入可能なProductIdの一覧を返すことを想定している。


2.購入事前処理URL

プレイヤーがストア画面などでプロダクトを選択、購入しようとした際、クライアントがこのURLにPostで通信する。

ゲームサーバはこのプレイヤーが特定のプロダクトの購入を試そうとした旨を記録し、実際に購入終了/キャンセル時の処理に際して付き合わせができるように

購買情報を記録することができる。

特にTicketId(購買に関して、開始時に付与されるId)をレスポンスで返すことを想定している。


3.購入事後処理URL

プレイヤーがストア画面などでプロダクトを選択、購入完了か、キャンセルした際、クライアントがこのURLに通信する。

クライアントは事前に発行されていたTicketIdと購買/キャンセルされたプロダクトの情報をゲームサーバにPostで送付する。

ゲームサーバ側は、送付されて来たTicketほかを比較し、課金完了のための処理を行うことができる。



AssetBundle系

1.AssetBundlesList取得URL

AssetBundle機能を初期化した際に、クライアントがこのURLへとGetで通信する。

現在のバージョンのアプリケーションで使用されるAssetBundleの一覧情報のリストを返す。


2.PreloadList取得URL

中略


3.Asset取得URL

中略 だいたいCDN



メンテナンス系

1.メンテ情報取得URL

中略


wrote 2017/01/27 4:37:48

Quicの話 ある日のミートアップ


概要


udpが通じない場合はhttp/tcpにフォールバックしてる


壮大なABテストされてるなあ。


PCの方がモバイルよりも受けてる恩恵が小さいのはなんでだろう

・まずこれらを比べることは困難

・データセンタへの接続とか、IPの変更がエフェクト出してる。改善率が低いのはそのせい?



いろいろ前提がよくわからん図

でも改善するための指標としてこういう実験が背景にあるのはすごく羨ましい。

解決すべき問題に対して理解が深められてそう



Rebuffer rateが100%になったケースが93%なるほど


クソ遅い環境(インドとか300msRTT medium)に対して、8%の改善があったみたいな話

なるほどな~遅い環境ほど改善率がある技術。底上げができる感じ。


sigcomm QUIC 2017あたりで検索するとデータが引っかかるようになりそう。



別の話



HTTP over QUIC



1本のstreamにはヘッダがカウンターしてる

- 3,2,1 ->

<- 1,2,3 -

・他のにデータが流れてる


か、

ヘッダに1本

データに1本


のペア x N になる(予定?)


フレームタイプの削除

WINDOW_UPDATE, PING, RST_STREAM, GOAWAY とかはquicが提供する。


セッティングの交換

quicがハンドルするんでいろんな設定が消えるが、

どうやってそれを周知するか(ack)



セッティングのack

SETTINGS_ACK 

これが送られてくるstreamが最後のstream(それ以下のstreamしか使われない


そのへんが使われる。



header compression

udpなんで順番は全くない。で、通し番号を振ると、HoLが発生する。

ので、

qpackでは別のアプローチを取る。


qpack(wip


insert key=value at INDEX INDEX 1 0 key value

reference iINDEX、、、みたいなのを定義してる

参照の証みたいなのを送り返してくるのか。


「QPACK(work in progress)。ダイナミックテーブルのスロット番号を指定してテーブルに追加。パケロスの結果、インデックス参照が先に届いちゃった場合はブロックする 」


「テーブルからの削除も明示的に送る。参照がパケロスで遅れる場合があるので、使用回数を削除コマンドに含めておく。送信側で使った回数だけ受信側で使ってなければパケロスあったとわかる」

図がいっぱいあったので見て理解したい。



state machine オブ でかい





wrote 2017/01/25 19:39:10

Dockerのvolumeとかの情報を確認する


概要

やったことなかった。なるほどこうすればわかるのか。

DockerのVolume機能について実験してみたことをまとめます

http://qiita.com/namutaka/items/f6a574f75f0997a1bb1d





wrote 2017/01/15 15:19:20

Miyamasuアプデしてた ~GUIなしPlayerモードで非同期テスト最高~


概要

そのうち「2017 Unity 春の自作テストツール祭り」みたいなのをやるので、それに出品(?)する。


非同期テストも書けるリモートテストランナー兼、なにかになった。 ver 1.3.0。


そんな Miyamasu

https://github.com/sassembla/Miyamasu


アプデ内容

非同期テストが書けるUnity用のテストツール、みたいなの、みなさん自作してると思うんだ。

Miyamasuもそんな中の一つなんだけど、今回はいろんな実行モードを追加していた。


・Editor実行(既存)

・Player on Editor実行(改良)

・Player実行(新規、調整中)

・Batch Player実行(新規)

・CloudBuild実行(新規、頓挫中)


このうち、CloudBuild実行は、Miyamasu のユニットテストを搭載したプロジェクトをUnity CloudBuildにアップした際、

その上でテストが走る、みたいなモードなんだけど、

とにかくNUnitの使い方が残念なのと、Unityが非同期テストを軽んじてて辛いのでまだ実現できていない。



Editor実行(既存)

コンパイルが走るたびに自動的に実行できる。

ただし、PurchaseとAssetBundle周りの非同期コードが一部Playerでしか進捗しないため、それらのテストだけはできない。

人間が任意でtestをSkipするみたいな機構を入れることで回避した。


Player on Editor実行(改良)

これはそのまま、Play時にMiyamasuのテストケースが実行されるようになった。

いろいろ手が込んだことをした結果、通常のアプリケーションを走らせたままテストが可能になったと思う。



Player実行(新規、調整中)

書かれたテストを適当に実機とかでも実行できる。

もうちょい調整する。リモート実行、リモートレポートとかをガッツリ入れてて、面白いことになってる。



Batch Player実行(新規)

バッチ実行で、ヘッドレスのPlayerが起動するようにした。

ようはUnity Editor上でのPlayer状態でのTest実行を、batchから起動することが可能になった。


例えばAutoyaのリポジトリでこれを使ってて、sh run_miyamasu_tests.sh とかやると、UnityがUIなしで起動した状態で、Playerモードになった上でテストが走る。

課金とかAssetBundleとかの「非同期を含んでで、MainThreadでしか動かせない」系のテストも無事突破した。これってすごくない?

結構面白かった。



CloudBuild実行(新規、頓挫中)

具体的に言うと、NUnitのユニットテストでは、main threadを自由に回しつつ、main threadで他の処理を走らせつつ、非同期処理を待つ、ということができない。


これは、たとえUnityにasync/await とかが来ても、使い物にならないということを言おうとしてる。

代替策としてMiyamasu作ったんだけど、思ったよりも事態は辛い感じだった。


Unityの構造が~とか、NUnitが~~とかそういうのではなく、NUnitの使い方がダメ、みたいな話。

NUnitのユニットテストを起動すると、次のような特徴のある動きをする。

・テストはMainThreadで起動(PlayerモードでもEditorモードでもない、そのほかのモード


・テスト中、Instantiateとかをやっても問題ないので、PlayerのMainThreadか、EditorApplication.updateの属するスレッド(EditorMainThread)に近い特性を持つ。


・なおかつユニットテスト中、EditorApplication.updateは完全停止している(これはほんとに困った)


・例えば別スレッドで行われる非同期な処理など、特定の処理の終了を待つ方法がない(MainThreadなので、これをロックすると全てが停止する)


・じゃあ起動だけでもできればいいか、、と思って新規にスレッドを立ち上げると、そのスレッドからMainThreadに対してActionとかを放り込むことができないため、MainThread系のメソッドのテストができない


この文章読んだだけだとしっくりこないかもしれないが、

「非同期テストをするためには、非同期処理の完了を待たなければいけない」という常識的な操作に対して、NUnitの起動スレッドが、停止を許されないMainThreadであることが、致命的になっている。 たとえばawaitとかで「ほかのthreadが終わるのを待つ」という処理を書くと、もれなくUnityEditor全体が停止する。これだとTestが進まない。

ちなみにNUnitのテストでの SynchronizationContext.Current はnullなので、何もできない気がする。Playingの時かつMainThreadでのみ値が入って動くみたいだ。

http://stackoverflow.com/questions/9377290/synchronizationcontext-current-is-null-on-resolving-with-unity-in-wpf

なおかつ、UnityにはMainThreadでしかできない処理があるので、その処理を放り込む先 = MainThreadが停止してる ということがあるせいで、ろくなテストが書けない。

理想形を考える

理想形はどんななんだろう、って考えると、

・擬似メインスレッドで起動しつつ、実際のPlayerスレッドとは違って「メインスレッドをロックせずに特定の処理が終わるのをメインスレッドで待つ」という処理ができないといけない。

いっそ特殊なPlay状態にでもしちゃって、特定処理が帰って来たら処理復帰する、それまでは空回りする、

みたいなIEnumerator返す関数みたいな処理がテストユニットとして動作できるといいのになあと思う。


ようは、NUnitを使うにしても、IEnumeratorを返すようなテストユニットに改変しちゃって、MainThreadからユニットテスト自体をMoveNextさせられればいいんじゃないか。

まあMiyamasuがそれなんだけど。公式でもっとしっかりしたのがあると嬉しい。



適当なコードにするとしたらこんな感じ。


public class CloudBuildTestEntryPoint {

[Test] public static IEnumerator RunFromNUnit () {// IEnumeratorを返す、ユニットテスト単位の擬似MainThreadで実行されるNUnitのテスト処理


// 完了待ちをするbool

var done = false;



// 適当なGameObjectを作成

var go = new GameObject("test");

var mb = go.AddComponent<MainThreadRunner>();

// 別スレッドでテストを実行する処理(IEnumeratorを返してくる)。

// mbを取り込んで、MainThreadでやってほしい処理を実行させる。

// ここの書き方はどうでもいい。

RunOnAnotherThread(

() => {

var path = “test:”;


// mbに対してMainThreadで実行して欲しいiEnumeratorを送って、mbのUpdateで実行する = MainThreadに処理を放り込む。

mb.Commit(

() => {

path = path + Application.dataPath;// このメソッドはMainThreadでしか呼べない

}

);


// なんか非同期処理


done = true;

}

);

// 上の処理が終わるまでここで空回りさせる

while (!done) {

yield return null;

}

// なんかAssertとかの処理

}

}


公式でないと作れないのが、「PlayモードでなくてもPlayモードと同じように動く、ユニットテスト単位で後片付けとか上手な機構」という感じで、

こういうのがうまく書けるようになるといいな~~と思う。


何度も言うけどMiyamasuはそれができてるんで、まあ、公式でないのが欠点。


wrote 2017/01/10 2:20:24

Unity IAP サーバ側で検証~みたいなのを実装してた


概要

簡単だった。いや~~楽になったなあ。

もうSoomlaもPrime31も要らないと思う。


困るのは使い方を知るための情報が足りなかったりとかそのへんだ。


一番悩んだのが、payloadっていう引数があったんだけど、これがどう扱われるのかまったくドキュメントがないところ。


Mac/iOSのreceiptにはそんなの入る枠ないし、となるとAndroidでのpurchase receiptにのみ関連するんだろうか、、?


入っているのか入っていないのか、というめんどくさいけど確認しないとわからなかったのでそのまとめ。



Unity IAP API

なんかこう書くとややこしいんだけど、十分実用に耐える感じ。


・ストアの初期化

・Purchaseの発行

・ユーザーアクションのハンドリング

・Purchase完了時の同期的完了処理

・Purchase完了後の非同期的完了処理

・その他 プラットフォーム独自の要素の設定とかいろいろ


といった物事が綺麗にハンドリングできる。



サンプルを作るにあたって苦労したこと

今作っているAutoya フレームワークにエッセンシャル的な実装をぶち込んだ。

payloadの次に悩んだのが、Purchase完了後の非同期的完了処理。


いやドキュメントが足りなくて。具体的には次のことをするための情報がなかった。

・非同期に処理するには、まずPendingする必要がある

・サーバの応答を待って、対象のProductをcontroller.ConfirmPendingPurchase(e.purchasedProduct)する必要がある

・今PurchaseしたProductと、過去PurchaseしていてStore処理が未完だから流れてきたProductを綺麗に見分ける必要がある

・payloadがどんなデータになるのかよくわからん



綺麗に見分けるという動作のニーズ

UnityのIAP APIでは、購入が完了していないProductはOS(iOS, Android)が適当なタイミングでその情報を流してくるのをラップしているので、

PurchaseProcessingResult ProcessPurchase (PurchaseEventArgs e){} 

がいつでも呼ばれる可能性がある。


これは、たった今購入したProductに対しても呼ばれるし、先ほど行ってまだ完了していないProductに関しても呼ばれたり、

あまつさえ別端末で同じIDでログインしてたりすると、そちらで完了していなければ別端末で受ける、みたいなのもある。


つまり「アカウントに紐づいて、今買ったProductも、こないだ買った未完了のProductも、このメソッドを呼び出す」のだ。

これがめんどうくさい。綺麗に見分けないといけない。

「Productは購入されてるんだけど、今買ったの? それともこないだ買ったの?」というのを判断しないといけない。

綺麗に見分けるという動作の実装

で、ProductにはtransactionIdというパラメータがあるんだけど、

このパラメータは「購入処理が開始されてからセットされる」。


つまり事前に設定できるパラメータではない。


・購入用のIdを適当に用意する

・そのIdをProductとまとめてStoreに流して、Product情報から取り出す


ということができれば、他のProductと明確に区別できるんだけど、まあ、クライアント側でそれらを処理間で共有するようなキーはAPIに存在しなかった。

唯一、

controller.InitiatePurchase(product, payload);

のpayloadがなんかそれっぽかったんだけど、このパラメータはまあ、御察しの通り、Androidのreceiptの内部に入れられるパラメータだった。

んでこのpayload、具体的なreceiptに入るよ~~とか説明一切ないの。なんかpayloadだよってだけで。困る。


最終的にどうやったかというと、Productのインスタンスを自分で保持する、ということにした。


購入前

-> ProductIdでProduct召喚

-> オンメモリでProductを保持(グローバルなパラメータとして保持)

-> 購入処理

-> 購入成功でProcessPurchaseが呼ばれる

-> オンメモリに保持していたProductのインスタンスのtransactionIdが処理を経て変わっているので、そのtransactionIdと、ProcessPurchaseで渡ってきたProduct(オンメモリのものと同一)のtransactionIdを内容比較

-> 一致すればたった今購入したProduct、一致しなければ今買ったのではないけれどまだ未処理のProduct という区別ができる。


はーー。これだけのことをするために「どうすればいいんだろ。。?」ってなってた。

ちなみに public void OnPurchaseFailed (Product i, PurchaseFailureReason failReason) メソッドも似たような呼ばれ方するので、やはり判別する必要がある。



おねがいドキュメント。オンメモリで購入中のProductのインスタンスを保持すればいいですよ、ってどっか書いといて。

パラメータの内容が動的に変わるからそれ使ってトレースできるよ、っていうのはちょっと、、、ノールックはちょっと、、、、まあ、、、はい、、、

wrote 2017/01/05 17:46:38

qdanshitaのチューニング紹介


概要

nginx-luajit-websocket-udp、略してqdanshitaになった。

各機構の設定の関連性や、ログ、チューニングについて書く。

あとベンチマーク用にlocustスクリプトを用意したので、それについても書く。


リポジトリはここ。

https://github.com/sassembla/nginx-luajit-ws/tree/benchmark-with-netcore


機構構成

nginx + lua(micro websocket server per connection)、

nginx stream + go-udp-server(udp receiver/sender)

disque(upstream/downstream message queue) を組み合わせた機構。



特性

・1ユーザーにつき、消費するポートはユーザ接続tcp1つ + disque-nginx up/down tcp2 の3つ。

・queueを挟むため、負荷に強い。

・upstream(上流サーバ)を完全非同期に実装できる。この仕組みは、ゲームロジックをbackpressureの負荷を考えずに実行するのに役立つ。



接続とデータフロー

0.マッチング、接続に必要なパラメータを取得

1.クライアントとの間にudpでのデータ送付経路を確立

2. 0,1で取得したパラメータを使って、websocketでの接続を行う。


udp接続の手順はスキップすることができ、その場合downstreamでのudp送付は発生しなくなる。(要luaカスタマイズ)


接続後、udp、wsを介してdownstreamのデータがサーバからクライアントへと送付される。



nginx.conf、lua、go-udp-server、disqueのセッティング

nginx.conf

nginx.conf(https://github.com/sassembla/nginx-luajit-ws/blob/benchmark-with-netcore/DockerResources/nginx.conf)

workerごとの接続数などを設定する。


nginx streamで8080ポートで受け止めたudpを8081ポートで待つgo-udp-serverへとproxyしている。


urlに対してluaファイルのパスを指定、ルーティングを行う。

サンプルでは、次のような記述で、http://SOMEWHERE/sample_disque_client へと到達したリクエストを、sample_disque_client.luaスクリプトへと転送する。

# sample disque client route.

location /sample_disque_client {

    content_by_lua_file lua/sample_disque_client.lua;

}




lua

/luaフォルダ以下に入っている。

nginx.confのルーティングから呼ばれ、リクエスト時に実行される。

セッティング、リクエストヘッダ値の読み出し/分岐、そのパラメータを使った認証機構を入れる箇所がある。

また、upstreamが リクエストurl末尾path + _context というqueue名でdisqueからデータを引き出せるようになっている。


sample_disque_client.lua(https://github.com/sassembla/nginx-luajit-ws/blob/benchmark-with-netcore/DockerResources/lua/sample_disque_client.lua)

-- get identity of game from url. e.g. http://somewhere/game_key -> game_key_context.

UPSTREAM_IDENTIFIER = string.gsub(ngx.var.uri, "/", "") .. "_context"


-- message type definitions.

STATE_CONNECT           = 1

STATE_STRING_MESSAGE    = 2

STATE_BINARY_MESSAGE    = 3

STATE_DISCONNECT_INTENT = 4

STATE_DISCONNECT_ACCIDT = 5

STATE_DISCONNECT_DISQUE_ACKFAILED = 6

STATE_DISCONNECT_DISQUE_ACCIDT_SENDFAILED = 7



---- SETTINGS ----


-- upstream/downstream queue.

DISQUE_IP = "127.0.0.1"

DISQUE_PORT = 7711


-- CONNECTION_ID is nginx's request id. that len is 32. guidv4 length is 36, add four "0". 

-- overwritten by token.

CONNECTION_ID = ngx.var.request_id .. "0000"


-- go unix domain socket path.

UNIX_DOMAIN_SOCKET_PATH = "unix:/tmp/go-udp-server"


-- max size of downstream message.

DOWNSTREAM_MAX_PAYLOAD_LEN = 1024



---- REQUEST HEADER PARAMS ----



local token = ngx.req.get_headers()["token"]

if not token then

    ngx.log(ngx.ERR, "no token.")

    return

end



local udp_port = ngx.req.get_headers()["param"]

if not udp_port then

    ngx.log(ngx.ERR, "no param.")

    return

end


---- POINT BEFORE CONNECT ----


-- redis example.

-- このままだと通信単位でredisアクセスが発生しちゃうので、このブロック内で、なんらかのtokenチェックをやるとかするとなお良い。このサーバにくるはずなら~とかそういう要素で。

if false then

    local redis = require "redis.redis"

    local redisConn = redis:new()

    local ok, err = redisConn:connect("127.0.0.1", 6379)


    if not ok then

        ngx.log(ngx.ERR, "connection:", CONNECTION_ID, " failed to generate redis client. err:", err)

        return

    end


    -- トークンをキーにして取得

    local res, err = redisConn:get(token)

    

    -- キーがkvsになかったら認証失敗として終了

    if not res then

        -- no key found.

        ngx.log(ngx.ERR, "connection:", CONNECTION_ID, " failed to authenticate. no token found in kvs.")


        -- 切断

        redisConn:close()

        ngx.exit(200)

        return

    elseif res == ngx.null then

        -- no value found.

        ngx.log(ngx.ERR, "connection:", CONNECTION_ID, " failed to authenticate. token is nil.")


        -- 切断

        redisConn:close()

        ngx.exit(200)

        return

    end


    -- delete got key.

    local ok, err = redisConn:del(token)


    -- 切断

    redisConn:close()


    -- 変数にセット、パラメータとして渡す。

    user_data = res

else

    user_data = token

    CONNECTION_ID = token

end


-- ngx.log(ngx.ERR, "connection:", CONNECTION_ID, " user_data:", user_data)




---- CONNECT ----

...


go-udp-server

/goフォルダ以下に入っている。


main.go(https://github.com/sassembla/nginx-luajit-ws/blob/benchmark-with-netcore/DockerResources/go/main.go)

をコンパイルして起動しておく。

デフォルトでは8081ポートでudp接続を受け付け、tmp/go-udp-serverという名前のunix domain socketを読み込む。

nginx stream機構の下で動くのを基礎としていて、nginxは8080/udpでudpを受け付け、8081 go-udp-serverへとデータをproxyする。


起動時にオプションを渡すことで、デフォルト設定を上書きすることができる。centosなどを使う際は適当に指定するといいと思う。


--portオプションでudpを待ち受けるポートを指定、

--domainオプションで、unix domain socketのパスを指定する。


負荷が高くなるとlua側で shared connection is busy while proxying connection ログが出る。ただ、これが出る状態がすでにコア数に対してnginxのworkerがサチっている



disque

disque-serverを別途起動しておく。

起動時に --maxclients 100000 とかつけておくと、disqueのデフォルト値の10000以上の接続が可能になる。


luaから接続 -> disque -> upstreamへとデータを送り、

upstream -> disque -> lua -> クライアントへとデータを送る中継点に使われる。


Upstream

要はServer。


サンプルとして、約60fpsでクライアントへとechoを行うdotnet coreの機構を用意してある。

https://github.com/sassembla/nginx-luajit-ws/tree/benchmark-with-netcore/DockerResources/csharp



ログ

接続、切断、エラーなどの基本的な情報は、すべてnginxのerror.logに出るようになっている。

デフォルトでは切断時、エラー時のみログを出力している。


出力もとはluaなので、編集したい場合はそちらを。



チューニング

nginx error log

-> max number of clients reached

-> disquemax connection設定を上回る接続がdisqueに来た。 デフォルトは10000、disqueを--maxclients 100000とかつけて起動すればOK。


-> too many なんちゃら、worker なんちゃら

-> nginx.confにworker_rlimit_nofileやworker_connectionsの設定があるのでいじると良い。

Nginxのパフォーマンスを極限にするための考察

https://qiita.com/iwai/items/1e29adbdd269380167d2


-> shared connection is busy while proxying connection

-> luaからgo-udp-serverへとudpデータを送付する際に、nginx luaのソケットIOの限界を超えていると発生する。



クライアント側エラー

-> connection refused, reset by peer

-> サーバのtcp/ipのソケット数限界に達している可能性が高い。

ubuntuだったら echo 1024 65535 > /proc/sys/net/ipv4/ip_local_port_range とかでパラメータ変えればいい。


disquuun部分の負荷が高い

-> disquuunの初期化パラメータのコネクション数を増やすことで負荷が下がるケースがある。

60fps 10msg/sec up/down 5000接続以上で動く場合は、30接続くらいでいい予感がする。それ以上あげてもスペックが変わらない。


また、各ユーザー向けのデータを送付時に各ユーザー単位でまとめると負荷が下がる。

理想は1fあたり各ユーザーに対して1通の送付にできるといい。

go-udp-serverの負荷が高い

-> 20~30%くらいはよくある感じ。

メッセージ送付の数にそのまま関連するので、downstreamのメッセージ数を見直すと解消しやすい。


各パーツの有無による負荷変動について

lua <-> disqueのメッセージのやり取りは、nginxのworkerへの負荷がわずかにある。


これはworker数が多ければ多いほど各workerの負荷が減るので、スペックが伸びる。

4コアのマシンで 60fps 10msg/sec up/down を実施させたところ、6000接続を超えたあたりからクライアントへのデータ送付がわずかに遅れるケースが散見された。



nginx workerに負荷がかかるとどうなるか

・クライアントへと届けるdownstreamが遅延する。ここが遅延するのは、各workerの負荷が40%とかを超えてから。worker数が多ければ避けられる。

worker数を増やす、downstreamへのメッセージをまとめる、などで負荷が軽減できる。



disqueに負荷がかかるとどうなるか

・あまり問題が起こらない。メッセージの到達遅延につながったことはないっぽい。

もし負荷が気になる場合、luaを改変してworkerごとに異なるdisqueにつながるようにするといいと思う。



upstreamに負荷がかかるとどうなるか

・全体のメッセージの流れが遅延する。

upstreamのメッセージの吸い出しが遅くなり、

downstreamのメッセージの送付が遅くなる。


メッセージの消化不良が溜まっていく以外に影響はでない。

ただし、メッセージの消化不良が起こると、disqueがどんどんメモリを食っていくことになるので、

その辺に関して注意が必要。メッセージサイズが小さい + メッセージをまとめて扱うような工夫が効果が高い。



go-udp-serverに負荷がかかるとどうなるか

・あまり問題が起こらない。メッセージの到達遅延につながったことはないっぽい。

負荷が気になる場合、新規にポートを指定してgo-udp-serverを追加し、nginx.confへとポート情報を加える。

すると自動的に複数のgo-udp-serverへとデータが流れるため、負荷が分散できる。



locust

ベンチマークはlocustを使って行なっている。

使用しているlocust fileは、https://github.com/sassembla/nginx-luajit-ws/tree/benchmark-with-netcore/locust に動作するものを置いてある。


サンプルはDockerコンテナで動作するものになっていて、

ubuntuなどに放り込んで、rebuild.shを実行すれば起動、その後ポート8089にアクセスすれば接続と負荷掛けを実行できる。



デフォルトで設定されている負荷は、

・1locustごとに1接続

・1locustにつき秒間10件程度のデータをサーバに送り、サーバから秒間10件程度のtcp + udpでのエコーを返す

・接続が確立されたり、切断されるとlocustのコンソールにメッセージやエラーが表示される

・データを受け取っていない場合のwarningとして、1秒以上データを受け取っていないクライアントにwarningが出る



変更すべき設定は、接続先のサーバのIPとport。


locusts.py(https://github.com/sassembla/nginx-luajit-ws/blob/benchmark-with-netcore/locust/test/locusts.py)

    server_ip = "150.95.211.59"

    # server_ip = "127.0.0.1"


    server_port = 8080

    message_per_sec = 100.0 / 1000.0

    server_path = "sample_disque_client"


server_ip、

server_port、

message_per_sec:メッセージを秒間何件クライアントから送付 -> サーバから返送するか

この記述だと100.0 / 1000.0 = 0.1で、秒間10件送付する。名前間違えたな。。


server_path: url末尾につけられるパス。server_ip:server_port//server_path になる。

wrote 2017/01/05 14:05:34

よく見たらUnityのIAPにMiniJsonが入ってた話


概要

コード見たらこんな感じだった。


namespace UnityEngine.Purchasing

{

    public static class MiniJsonExtensions

    {

        public static List<object> ArrayListFromJson(this string json);

        public static T Get<T>(this Dictionary<string, object> dic, string key);

        public static bool GetBool(this Dictionary<string, object> dic, string key);

        public static T GetEnum<T>(this Dictionary<string, object> dic, string key);

        public static Dictionary<string, object> GetHash(this Dictionary<string, object> dic, string key);

        public static long GetLong(this Dictionary<string, object> dic, string key);

        public static string GetString(this Dictionary<string, object> dic, string key, string defaultValue = "");

        public static List<string> GetStringList(this Dictionary<string, object> dic, string key);

        public static Dictionary<string, object> HashtableFromJson(this string json);

        public static string toJson(this Dictionary<string, string> obj);

        public static string toJson(this string[] array);

        public static string toJson(this Dictionary<string, object> obj);

    }

}


UnityEngine.Purchasing には、MiniJsonExtensionsっていう名前で、いろんなものをJsonに変えるメソッドがついてる。

というわけでMiniJsonを自前で使うのはもう考えなくていいんじゃないだろうか。


2017年もよろしくお願いします。



-> 追記 2017/06/22 14:31:51

新しいIAPのバージョンには、これらの拡張メソッドは含まれないようになったみたい。エディタとかで楽できてよかったのだけれど。

まあ型を書こうぜ、ってことで。


さよならMiniJson。


wrote 2017/01/03 0:17:33

AssetBundleGraph作ってみた 気持ち全国から選りすぐりのサンプル集を大公開!


概要

本稿はUnity アドベントカレンダー (2) 12/23日の記事になる。

http://qiita.com/advent-calendar/2016/unity2


昨日はEllise_MXさんの[Unity+FuelPHP+PhotonNetworkでオンラインゲームの基礎作り]でした。

明日はmurapongさんの、[Unity Cloud Buildのビルド結果をHipChatに通知するには]です。


AssetBundleとかUnityのAssetの設定とかをとにかく力強く楽に扱えるツール「AssetBundleGraph(ABG)」の話をする。


あと実は、このページはUnibook 総集編からも参照されている。



今回のお題目

AssetBundleGraphの使用例などを公開できればとおもう。

Unity 5.4.2で試している。



AssetBundleGraph

いろいろあって、UnityのAssetBundle(ほか)をフロー形式で作り出すツール制作のお手伝いをしていた。


これ。

新しいアセットバンドルツールのプロトタイプ

https://blogs.unity3d.com/jp/2016/10/25/new-assetbundle-graph-tool-prototype/



で、かかわった動機とか経緯とかは過去の記事にあるので興味のある人はどうぞ。うかつに人にいちゃもんをつけに行くと色々なことが起こるのがよくわかった。

http://sassembla.github.io/Public/2015:04:13%2019-06-37/2015:04:13%2019-06-37.html

-> 自作のAssetStoreにあるやつをプレゼンする -> じゃあお前やれよ(丸みを帯びた表現) -> ニュースリリースと。



すでに自分の手は離れており、BitBucket上でゴリゴリと開発/改良/改善が進められている。

で、今回はそんなAssetBundleGraphのサンプルを何パターンか作ってみよう、みたいな話。 だいじょうぶ、ファミ通でもなんでもない攻略本だよ。



!!注意!!

大事なことを言い忘れてた。


AssetBundleGraphは

AssetBundleを作るためだけに使えるツールでは

ない!!!


このツールは、いままで手でやっていたUnityのAsset一個ずつに対しての操作を、ルールベースでとにかく大雑把かつ人間より正確にサクッと実行する、というツールなのだ。


iOS用に全ての画像の設定を変えたりとか、英語版だからこのグラフィック使おうねとか、これらのモデルの設定を全部ああしますとかそういうのを

適当にまとめて実行できる

のだ。


複数のAssetから複雑なプレファブ作ったりするのも

適当にまとめて実行できる

のだ。プレファブまわりはさすがにちょっとコード要るんだけど。


たまたまその動作の一つとして

AssetBundleを作れる

というのがあるだけなのだ。


では例の紹介に行ってみよう。


AssetBundleGraph使用例6本ノック

取り上げさせてもらったネタはこちらのシートにあるやつのいくつか。

https://docs.google.com/spreadsheets/d/1jHv8mFy2HhnnXCRr0tXHRLzt0ve4xGJebas8Q9R31Mo/edit?usp=sharing



サンプルモリモリのリポジトリはこちら。

Advent2016_AssetBundleGraph

https://github.com/sassembla/Advent2016_AssetBundleGraph


サンプルはそれぞれブランチに分かれている。



各内容の解説は下の方に書いて行く。長い。



リポジトリにあるようなAsset生成が捗る環境を、手元に用意するには

readmeにも書くつもりだけれど、短いのでこちらにも書いておく


1.適当なリソースの入ったプロジェクトを用意する

もちろん、「あっAssetBundleGraph使ってAssetをゴインゴインしよう」っていう対象のAssetがいっぱいあるリポジトリとかでいいと思う。

もしくは、適当に空のプロジェクトを作って、適当に画像とかモデルとかをAssetsフォルダ以下に入れたものを用意するのでもいい。


2.bitbucketのライブラリからAssetBundleGraphをDLする

https://bitbucket.org/Unity-Technologies/assetbundlegraphtool/downloads


3.ダウンロードしてきたAssets/AssetBundleGraph フォルダを、1で用意したプロジェクトのAssetsフォルダに放り込む

準備は以上!


4.使う

メニュー > Window > AssetBundleGraph > Open Graph Editor で、グラフのウィンドウが表示されるので、右クリックでノードを作ったりいろいろする。



やりたいこと募集中(だった。)

なにぶんグラフィカルになんとかするのに特化してるツールなんで、とっつきやすいが深堀りするとなるとまあ、

本家のAssetBundle作りにならう感じで、まあ、例がない。


みなさんがやりたいことはたくさんあると思うんだけど、そのための例がない、という状況はめっちゃ肌感的に共感できるつもり(傲慢


というか自分が「わからねえぞ、、なんだこれはどうやればいいんだ、、」って思ったことがあるのもあって、少しでも人の理解を手伝いたい。

今回は最新版を使うのだけれど、自分が関わっていた時(だいたい今年の5月とか6月)より遥かにパワーアップしていた。恐ろしいツール。


なので、こう、


「こんなリソースをAssetbundleGraphで作るにはどうすればいいのか?」 みたいなリクエストを募ろうと思う。

まあ、気長に。


宛先はこちら。

AssetBundle(ほか)制作やっていき隊

https://docs.google.com/spreadsheets/d/1jHv8mFy2HhnnXCRr0tXHRLzt0ve4xGJebas8Q9R31Mo/edit?usp=sharing



ちなみに、

ラジオのお葉書みたいな感じで、稀に読み上げて参考にすることはあっても、絶対に応答があるわけではない。ごめん。



べつにAssetBundleGraphを使って解決しないかもしれないけど、別の手段はありそうな感じで。

みたいなことが書いてあったんですよ。アドベントカレンダー当日までは。


さてやっとここから、公募で適当に集まった例を実際にAssetBundleGraphでなんとかしてみたものの説明になる。

各お題は、同名のブランチがリポジトリ(https://github.com/sassembla/Advent2016_AssetBundleGraph)にあるので、それをDLしながら眺めてもらえるとわかりやすいと思う。



複数の素材のセッティングを一括変更する

「この種類の画像はGUIに使うので、まるっと全部UI用の設定がしたい」、とかの要望があると思う。

あるいはもっと複雑な、「TextureのタイプをAdvancedにして、wrapモードをこれに変えて、そんでループを、、」とかをいちいち全部手でやると発狂しかけると思う。

そしてさらに、素材が入っているフォルダを分けたりするのが人情。一括での設定変換をこれでもかといわんばかりに難しくしてくれる。


そんな時、いちいちGUIから設定を変えることなく、一括で大量のファイルの設定を変更できる機能のデモが、このブランチ。


まず、グラフを右クリックして、Loaderノードを置く。

0.png

クリックすると、Inspectorが開く。で、ここでは、Assets/Game/Images っていうフォルダにサンプルとしてユニティちゃんとかの画像が置いてあるので、

その画像を読み込む(Loadする)ようにしてみる。

1.png

ちなみにAssets/Game/Imagesの中身はこんな感じ。画像いろいろ。

スクリーンショット 2016-12-22 2.02.36.png


次に、グラフを右クリックしてImportSettingsノードを追加。

スクリーンショット 2016-12-22 1.59.58.png

選択すると、Inspectorにこんな感じの見慣れないボタンが表示される。

で、Configure Import Settings ボタンを押すと、

スクリーンショット 2016-12-22 1.59.59.png

Loaderがロードしてきた画像のInspectorに切り替わる。

さてとりあえず設定を弄ろう。

スクリーンショット 2016-12-22 2.00.12.png

Advancedに変えて、いろいろ変えて、、、

スクリーンショット 2016-12-22 2.01.51.png

で、設定を適応させる。ここまでは通常通りのImportSettingsの手順。

スクリーンショット 2016-12-22 2.02.01.png


AssetBundleGraph実行!!(右のほうのBuildボタンを押す

スクリーンショット 2016-12-23 3.23.40.png

そして、先ほどの画像が置いてあるフォルダを覗いてみると、、

スクリーンショット 2016-12-22 2.02.36.png

すべての画像のセッティングが、先ほどセットした一枚の設定とクリソツになっている!

スクリーンショット 2016-12-22 2.02.41.png


やったぜ!


置いたノードは2つだけだが、

・特定のフォルダにある画像全部に対して同じ設定を行う

というのが瞬殺できた。


応用としては、

複数のフォルダの画像を、複数のLoaderノードで読みこんで、一つのImportSettingsノードに流し込んで、全部一発で設定したり、

このフォルダ以下の画像で名前にUI_って含んである画像は~ みたいな分岐も作り出せる。(Filterノードを使う


また、ImportSettingsノードは、画像だけでなくAudio、Modelに対しても対応しているので、それらにも同じようなことが実現できる。

それ以外のAssetでは、Modifierノードを使うといい感じに編集できそう。



複数の素材からプレファブを作る

Prefab(プレファブ)を作成する、というのが、これが数がかさんでくると重労働だ。

たとえばPrefabの構成に変更があった時とか、手でやってると正直しんどい。ミスも出る。

じゃあスクリプトを書いて自動化する? その自動化するコード毎回全部書くの?


という煽りに対して、AssetBundleGraphはわりといい感じの答えを用意してくれている。

PrefabBuilderノードを使うのだ。


まず、ユニティちゃんsの画像が入ったフォルダを、下記のように「キャラごとに」用意する。

スクリーンショット 2016-12-22 2.11.30.png

各フォルダの中には、各キャラの立ち絵が6枚ずつ入っている。

今回はこの各キャラ6枚の絵を、アニメーションとしてTexture2Dの配列に格納したPrefabを、各キャラごとに一つ作る、というのをやってみる。

prefabの要件はこんな感じ。

・prefabを3キャラ分、各キャラ一個作る

・prefabの内容は、GameObjectに特定のScriptがセットされている & ScriptのTexture2D[] texturesには各キャラのTextureが6枚ずつセットされている。

さて、やっていこう。

とりあえず素材を用意した段階で、フォルダ名に注目してほしい。

スクリーンショット 2016-12-22 2.11.30.png

フォルダ名は、chara_キャラ名 という感じで、ルールをもたせてある。

このルールを利用して、prefabづくりを簡単にすることができる。


そしてprefabになるGameObjectにセットするScriptだが、これは自分で用意する。

サンプルでは Assets/MyCubeScript.cs というScriptを用意した。


MyCubeScript.cs

https://github.com/sassembla/Advent2016_AssetBundleGraph/blob/%23複数の素材からプレファブを作る/Assets/MyCubeScript.cs

内容は至って簡単、Texture2D[] textures というパラメータを、lengthが6だと指定して初期化してあるだけ。


では、これらを使ってprefabを作る工程に入ろう。


まずはLoaderノードを置き、ロードする素材のパスをセットする。

スクリーンショット 2016-12-22 2.11.36.png

Assets/Game/Images フォルダ以下に上記の3キャラのフォルダが入っているので、指定。

スクリーンショット 2016-12-22 2.11.42.png

次に、Groupingノードを作成する。Loaderと適当につなごう。

スクリーンショット 2016-12-22 2.12.04.png

そしてGroupingノードを選択して、InspectorからGrouping Keywordを編集する。

スクリーンショット 2016-12-22 2.19.59.png

ここでは、<chara_*/> という文字列を入れている。


こう書くと、「chara_なにか/」というパターンで、

Loaderから流れてきているAssetのパスをもとに、

素材を複数のグループに分割することができる。

ちょっと何いってるかわからないので、仮にBundleConfigノードを作って置いてつないでみよう。

スクリーンショット 2016-12-22 2.20.09.png


18:3 みたいな表記が、接続線の上に表示されたと思う。このボタンを押すと、接続線を流れるAssetsの内容が、Inspectorに表示される。

お判りだろうか。18個のAssetsが、3つのグループに分割されているのが。

スクリーンショット 2016-12-22 2.20.10.png


お判りだろうか。Group Key: のところに、kohaku, misaki, yuko とかキャラ名が入っているのが。

Groupingノードでは、あらかじめフォルダ名にルールをつけておくことで、それらをグループ名にしてAssetsをグループ化することができるのだ。


いや~これ思いついた時は俺すげーって思ったよ。


で、


やりたいことは「これらのグループ化されたAssetsからprefabを作る」ということなので、

BundleConfigノードは一回消そう。


PrefabBuilderノードを作成する。と、エラーが出る。

スクリーンショット 2016-12-22 2.20.54.png


なになに? って選択してInspectorを見に行くと、

「PrefabBuilderにはPrefabBuilder scriptが必要だよ」と出る。

スクリーンショット 2016-12-22 2.21.39.png


すいませんそうなんです。script要るんです。

でもこれも作成できるんだよこのツール。

ツールバー > Window >AssetBundleGraph > Create Node Script > PrefabBuilder Script を選択。

スクリーンショット 2016-12-22 2.22.21.png

選択すると、scriptが作成されて、コンパイルが走る。

で、コンパイルが終わったら、PrefabBuilderを選択して、

PrefabBuilderというパラメータのドロップダウンをクリックし、MyBuilderを選ぼう。

スクリーンショット 2016-12-23 3.54.49.png


すると、PrefabBuilderノードにMyBuilderというコードがセットされ、

エラーが消える。


以降、PrefabBuilderノードが実行されると、MyBuilderというコードが自動的に実行されるようになる。

スクリーンショット 2016-12-22 2.22.22.png


MyBuilderのコードは、作成直後は雛形のような感じになっている。

コードは次のパスにある。

Assets/AssetBundlerGraph/Generated/Editor/MyPrefabBuilder.cs


内容はこんな感じ。解説は日本語でお送りします

MyPrefabBuilder.cs

https://github.com/sassembla/Advent2016_AssetBundleGraph/blob/%23複数の素材からプレファブを作る/Assets/AssetBundleGraph/Generated/Editor/MyPrefabBuilder.cs


やっていることは、

・CanCreatePrefab関数で、ABG実行前のRefresh時に実行される関数の結果として、入力されてくるデータのチェックや、チェックがOKだったらprefab名を返す処理を書く。このprefab名はABG実行時に使用される(その名前のprefabがダイレクトに作られる)。

・CreatePrefab関数で、ABG実行時に実行されてほしい処理を書く。


まずはCanCreatePrefab関数の内容を見る。

/**

* Test if prefab can be created with incoming assets.

* @result Name of prefab file if prefab can be created. null if not.

*/

public string CanCreatePrefab (string groupKey, List<UnityEngine.Object> objects) {


/*

この関数では、セッティングの途中で「どんなオブジェクトがAssetBundleGraphから流れてくるか」というのをチェックしたりすることができる。

ここでは各グループで6つずつのTextureが来るはずなので、

6枚テクスチャがあったらPrefabができる という予定で値を返してみる。

*/

if (objects.Count != 6) {

// 足りない!

Debug.LogError("texture shortage. groupKey:" + groupKey);

return null;

}


foreach (var obj in objects) {

if (obj.GetType() != typeof(Texture2D)) {

// テクスチャ2Dじゃない!!

Debug.LogError("obj is not Texture2D. obj:" + obj + " in groupKey:" + groupKey);

return null;

}

}


// 入力されてるアセット的にOKだったら、最終的に作るつもりのPrefabの名前を返す。

// ここでは、prefab_kohaku とかそういうのを想定している。

return "prefab_" + groupKey;

}


この関数はちょっと難解で、ABGが自動的に作ったテンプレっぽい内容を書き換えて、次のようなことをしている。

・objectsがテクスチャ6枚のセットであること

・もしそうだったら、”prefab_” + groupKey という文字列を返すこと

最後に返しているstringは、「無事にprefabが生成されたらこの名前にする」というパラメータになっている。

で、groupKeyという引数には、今回の構成の場合、さきほどGroupingで分けた、「kohaku」「misaki」「yuko」という文字列が入ってくる。

Groupingした素材のグループ観で切り分けられたリソースに対して、対応するようにこの関数が呼ばれるのだ。

これによって、

1.グループを作る

2.グループに対して処理をする(特にこの場合prefabを作る)


ということが大変やりやすくなっている。



で、次にCreatePrefab関数の中身を見よう。

/**

* Create Prefab.

*/ 

public UnityEngine.GameObject CreatePrefab (string groupKey, List<UnityEngine.Object> objects) {


// objectsの中身はTexture2Dなので、UnityEngine.ObjectからTexture2Dに変換する。

var textures = new Texture2D[6];

for (var i = 0; i < objects.Count; i++) {

var obj = objects[i];

textures[i] = obj as Texture2D;

}


// GameObjectを作成する。ここではCubeが好きなのでCubeを作る。

GameObject go = GameObject.CreatePrimitive(PrimitiveType.Cube);


// 今回Texture2Dを6枚セットする対象のスクリプトを、goにくっつける。

MyCubeScript myCubeScr = go.AddComponent<MyCubeScript>();


// myCubeScrのtextures(Texture2DのArray)に、ダイレクトにセット。

myCubeScr.textures = textures;

/*

最終的にGameObjectを返すと、そのGameObjectが自動的にPrefabになる! 

わあPrefabできちゃったよ。

名前はCanCreatePrefab関数で返したものが使われる。

*/

return go;


// そしてなんと、このGameObjectはこのあと自動的に消去される。

}


やっていることは、ものすごくダイレクトな感じ。


・ローカル変数 Texture2D[] texturesを作り、CreatePrefab関数の引数 objects として流れてくるAssets(全部Texture2Dのインスタンス)をセットする

・GameObjectを作ってMyCubeScriptをAddして、

・myCubeScrのtexturesというインスタンスに、冒頭で作ったtexturesをセット。


これで、あとはGameObject goを、この関数の返り値としてreturnするだけ。

するだけで、GameObject goは勝手に、キャラのテクスチャ6枚を含んだtextures配列 を持ったMyCubeScript がセットされた prefabになる。


このprefab、特にExportする先をExporterノードなどで指定しなければ、ABGのキャッシュ内に出力される。

具体的にいうと次の図のようなところに吐かれる。

スクリーンショット 2016-12-22 3.04.03.png

で、内容を確認してみると、、

スクリーンショット 2016-12-22 3.04.12.png

ちゃんと全キャラ全テクスチャがprefabとして計3キャラ分、全部セットされてる。やったぜ!


どうだろうか。

いままで手で書いてたコード、毎回構築していたルール、みたいなのと比べて、楽じゃねーかな?

素材を増やしたら勝手に種類が増えるし、スクリプトさえ変えれば処理も全部変化させられる。

複数のPrefabを作るにはどうすればいいのか?とかは、多分複数のPrefabBuilderを用意すればいいんじゃないかな~と思う。



プラットフォーム指定してコマンドラインから起動

これは比較的お手軽な方法が新規に実装されていて自分もビビった。

CIとかで実行したいじゃないですか。AssetBundle作るのとかそのへん。

というわけで実行できるし、実行するためのshellとかbatとかも生成できるんだよ、ABG。ホントびっくりだよ。


メニューバー > Window > AssetBundleGraph > Create CUI Tool を押すと、Macの場合shellが、Winの場合batが出力される。

スクリーンショット 2016-12-22 23.29.20.png

もちろん実行可能なやつ。


出力される場所は下記になる。

Assets/AssetBundleGraph/Generated/CUI/buildassetbundle.sh

スクリーンショット 2016-12-22 23.33.16.png


で、今回のサンプルでは、適当なグラフを用意したのと、それをプラットフォーム指定付きで実行するラッパーっぽいshellを用意した。


build_iOS_and_Android.sh 

sh Assets/AssetBundleGraph/Generated/CUI/buildassetbundle.sh -target iOS

sh Assets/AssetBundleGraph/Generated/CUI/buildassetbundle.sh -target Android



ABGの方ではどんなグラフを書いたかは、リポジトリ落としてGUIで見てもらうとして。

もうなんとなく察しはついたでしょ? -target でiOSとかAndroidとか書けば、対応するプラットフォーム向けにABGを動かしてくれるのよこのbuildassetbundle.shが。


プロジェクトフォルダ直下(Assetsフォルダと同階層)にあるExportパスを眺めながら、

build_iOS_and_Android.shを実行してみてほしい。

画像だとまずOSX版のAssetBundleを作っていたのを忘れてて、OSXフォルダがあるけど無視して。

スクリーンショット 2016-12-22 23.51.58.png

しばらくするとiOSフォルダが生成され、中身がモリモリ出てくる。

スクリーンショット 2016-12-23 0.07.20.png

さらに待つと、 Androidフォルダが生成され、やはり中身がモリモリする。


スクリーンショット 2016-12-23 0.14.35.png


ね。簡単でしょ(ボブ



完了後に独自の処理を行う

AssetBundleを作るのには、お世辞じゃないけど量に比例した時間がかかる。

やっぱりこれは変わらない。高速に実行するにはスペックで殴ったりキャッシュを効かせるのがいちばんいい。

で、時間がかかる処理なら、CIサーバとかで実行したい。そして完了したら通知が飛んでほしい。

というわけで「ABGの動作完了に合わせて、通知が飛んでくる」みたいなサンプルを用意した。

もちろん、ABGにはそのためのハンドラもある。全て熟知!!


メニューバー > Window > AssetBundleGraph > Create Node Script > Postprocess Script

で、ABGに関してのpostprocessのハンドラを含んだコードが出力される。

スクリーンショット 2016-12-22 24.47.53.png


出力場所はここ。 Assets/AssetBundleGraph/Generated/Editor フォルダ

スクリーンショット 2016-12-22 24.48.34.png

で、内容に関してはリポジトリを見てほしい。


MyPostprocess.cs

https://github.com/sassembla/Advent2016_AssetBundleGraph/blob/%23完了後に独自の処理を行う/Assets/AssetBundleGraph/Generated/Editor/MyPostprocess.cs

特にハンドラメソッド Runの末尾で、ビルドが終わった後に行う処理をC#で記述することができる。

このハンドラの引数には、「どのノードでどのAssetが処理されたか」を網羅する情報 assetGroups が入っているので、その情報を使ってビルド結果を通知することができる。



variantsでABの中身を指定する

というわけでvariantsを使ってAssetBundleの中身を制御するとか、まあ、そういうアレ。

サンプルとしては次のような要件を定義した。


・英語用の素材 en と、日本語用の素材 jp の2種のAssetを用意

・それぞれen、jp というvariantsを用意し、enを選んだら英語、jpを選んだら日本語用のAssetBundleを使えば良い、という状態を作る

・キャラ数分、3種類のAssetBundleを作る


ようはです。はい。


素材を次のようなフォルダ構成で用意。platform_enと、platform_jp という名前で各素材のフォルダを切った。

スクリーンショット 2016-12-23 2.30.25.png

enとjpの内容については、今回は全く同じフォルダ名で、これまた全く同じファイル名の画像を用意している。

variantsで差し替えられる素材の条件として、「全く同じファイル名」という条件があるので、画像のファイル名は必然的にこうなる。


早速次のようなグラフを構築してみる。

Loader > Filter > Grouping1,2 . BundleConfig > BundleBuilder > Exporter

スクリーンショット 2016-12-23 2.32.14.png

Loaderで読み込んだ画像群を、まずFilterでjpとenに分割している。

Filterからの出力先では、各3キャラクターそれぞれのAssetをAssetBundleにするため、Groupingを挟んでグループ化。


で、BundleConfigノード。こいつは大変シンプルな設定でものすごいことになっている。

入り口が3つあるやんけ。しかもjpとかenとか振ってあるやんけ。

スクリーンショット 2016-12-23 2.32.34.png

BundleConfigInspectorがこちら。

variantsがセットしてある

jpen2

スクリーンショット 2016-12-23 2.32.39.png

これで。これだけで。

BundleConfigに流れ込んでくるAssetに対して、variantsをセットして、同名のものがきちんと存在していれば、

variantsを含んだAssetBundleとしてビルドしてくれるんだよ。

すごい。


で、ABGをビルドした結果はこちら。

スクリーンショット 2016-12-23 2.32.40.png

はい、.enとか.jpとかできてますね。


manifestを見ると、いい感じになっている。



プラットフォームごとに異なる素材やimportSettingsを指定する

ほら、画像とかモデルとかオーディオとかだと、Inspectorからインポート時の設定をプラットフォームごとにセットできるじゃない。

AssetBundleGraphもそれができるよっていうやつ。しかももっとダイナミックな範囲で。


まずこのLoaderをみてくれ。こいつをどう思う。

スクリーンショット 2016-12-22 3.31.22.png



LoaderノードのInspectorはこんな感じ。

まあデフォルトでAssets/Game/Images/PNG_iOS っていうフォルダから画像読み出そうとするじゃない。

スクリーンショット 2016-12-22 3.33.15.png


アイコンがあるよね~~ってことは、そう、「もしこのプラットフォーム設定でABGを動かしたら、この設定が使われるよ」ってこと。シンプルかつ強力。

スクリーンショット 2016-12-22 3.33.24.png



で、プラットフォームの指定はABGの上部のバーのところをクリックすると、なんかいろいろプラットフォーム選択肢が出てくる。

スクリーンショット 2016-12-22 3.34.28.png


たとえばiOSとAndroidで別の画像素材を使って、別のImportSettingを適応させたい場合、次のようなグラフを書く。

LoaderノードとImportSettingsノードが一つずつ。

スクリーンショット 2016-12-22 3.34.34.png


この状態で、LoaderノードにiOS/Androidそれぞれの素材パスを書いて、

ImportSettingsノードに「iOSだったらこう」「Androidだったらこう」という設定をセットするだけ。

ね、簡単でしょ。


おわったああああああああ

良いお年を。なんか質問とかバグみっけたよとかあったら教えて、、くだ、、さ、、

明日はmurapongさんの、[Unity Cloud Buildのビルド結果をHipChatに通知するには]です。


http://qiita.com/advent-calendar/2016/unity2

wrote 2016/12/23 00:00:00

UnityでSingletonを頑張らずに使う


概要

そもそも複数のSingletonに頼らないといけない設計みたいなのがかなりアレだと思ってしまうのですけれど。

ニーズがあったので書いた。


gist SingletonHolder.cs

https://gist.github.com/sassembla/2de4e864bd0918a06761356398a0d02e


登録と削除のインターフェースを持ったSingletonを保持するクラスになっていて、

適当なクラスをSingletonとして登録することができる。


個々のSingletonを作るのではなく一元管理でき、

ゲームの開始と同時にシーンに関係なく自動的に初期化され、

なおかつ勝手にDontDestroyOnLoad属性が付くので、


管理の手間というか躓きポイントはあまりない。というかこういうのがないとSingletonとか怖くて使えないよね。



デフォルト性能

シーン間を超えたデータの保持を行うことができる。



おまけ特性 その1

UnityではMonoBehaviourのセットされたGameObjectを作っておくとMainThreadでMonoBehaviourの特定のメソッドが実行される。

で、割と、Singletonにしたいクラス = MonoBehaviourというケースがあったりする。

(自分で設計する場合はまずありえないんだけど、これはこれで、作ってわかる面白い副産物であった。後述のUpdateOnceとか。)


今回作ったクラスでは、あらかじめUnityのMonoBehaviourを扱うようにしているので、

SingletonにしたいクラスにUpdateとかを定義しておくと、ちゃんとMonoBehaviourで呼ばれるタイミングで呼ばれる。



このMonoBehaviour特性のせいで、MainThreadで特定のハンドラでもって特定の処理を1度だけ行う、みたいなのを実行できる。


例えば次のようなコードで、生成されてから一度だけUpdate関数が動くクラス を投げ込めばいい。


/*

Updateだけが定義してある、SingletonHolder.Baseを拡張したクラス

*/

public class UpdateOnce : SingletonHolder.Base {


    public override void Update () {


        Debug.Log("hello!!”);


        SingletonHolder.Delete<UpdateOnce>();// ここでこの型のsingletonが解除されるので、このUpdateの処理がMainThreadで一度だけ行われることになる。

    }


}


// どっかでUpdateOnceクラスのシングルトンを取得 -> UpdateOnceのインスタンスがsingleton化され、実行されるようになる

SingletonHolder.Get<UpdateOnce>();



おおーー思ったより便利かも。

UniRxのMainThreadDispatcherと原理は一緒。



おまけ特性 その2

登録すると、Hierarchy上でどのクラスのSingleton特性をもっているかが目視できる。


最初は空なんだけど、

スクリーンショット 2016-12-17 2.50.24.png



MySingletonクラスのシングルトンでもあるときはこんな感じ。

スクリーンショット 2016-12-17 2.52.01.png



はい。うん、みやすい。



葛藤

名前について、SingletonBed (つんく♂さんの歌のタイトルのパクリ)って名前にしようかと思ったんだけど思いとどまった。

褒めてくれ。



wrote 2016/12/17 2:55:31

Medium沼へようこそ


概要

チュートリアルやれば操作のすべてはだいたい漠然とそれとなく気持ち理解できるのだけれど、まだわからないところがあるので探しつつ遊んでる。

時間が溶ける。よいお肉くらい柔らかく溶ける。


なんかそれっぽい人型を作って悦に入っている(2体目くらいをワキワキしてる



これはね~~もうねーーーいいおもちゃだよ===~~

チートシート作ってる。



一作目 2016/12/08 2時間くらい

safe_image4.png


操作のチートシート用の画像をあとで追加するつもり。


公式FAQ

https://forums.oculus.com/community/discussion/45812/medium-frequently-asked-questions



簡単にaddとremoveを切り替えるには

右手のAボタンをダブルクリックすると、addとremoveが切り替わる。


Mediumからのexportどうなってんの

ボタンはある。二度押せば出力されるんだけど、なんかよーわからん。どこにexportされてるのこれ。



撮影したPhotoとかの画像ファイルはどこにあるの

Document/Medium/Photosにあった。



オブジェクト全体を移動する

視界(カメラ)に対する処理。

左右どちらかのトリガーを引いたままコントローラを動かすことで、オブジェクト全体を移動することができる。



オブジェクト全体を拡大縮小

視界(カメラ)に対する処理。

左右両方のトリガーを引いたままで、左右のコントローラの位置で、オブジェクト全体を拡大縮小することができる。




任意の単位での移動

レイヤー単位で操作ができる。

レイヤー表示モード(左スティック下げっぱなし)中に、左右どちらかのトリガーを引いたままコントローラを動かすことで、そのレイヤーに属するパーツを移動できる。

複数のレイヤーの左端のチェックマークをオンにすることで、複数のレイヤーに属するパーツをあわせて移動することができる。



任意の単位での拡大縮小

レイヤー単位で拡大縮小操作ができる。

レイヤー表示モード(左スティック下げっぱなし)中に、左右両方のトリガーを引いたままで、左右のコントローラの位置でそのレイヤーに属するパーツを拡大縮小することができる。

複数のレイヤーの左端のチェックマークをオンにすることで、複数のレイヤーに属するパーツを同時に拡大縮小することができる。



スタンプを自作する

左スティック下げっぱなし中にStampボタンを押すと、現在選ばれているレイヤーの形状のスタンプが登録される。

自作したスタンプは、Customという枠で保存される。



テンプレート

いまんとこできなそうなので、なんか一枚レイヤーに絵を書いてからやるとよさそう。



パーツを分割する

カットが対応する。

が、ちょっと癖があって面白い。

特にシンメトリモードみたいなのの時に、一本のシンメトリな棒の端に対してカットを行うと、パーツが地続きかどうかで

分割されるレイヤ構造が変わる。


具体例は後で追加する。


この癖は事前に設計にいれておかないと面倒臭そう。



ポリゴンのポイントを掴みたい

ない。その辺ごっそり捨てる設計になってるっぽい。

盛る/削るというUIに終始してる。



色をつける方法

素材自体に色をつける場合と、ポリゴンに対して色を塗る方法の2パターンがある。

両方とも解像度(ポリゴン密度)的には差がないみたいなんだけど、きちんと塗り分けしたい場合は出力した後にテクスチャで頑張る、みたいなのが必要そう。

いくらなんでもパーツ単位で色を全部分けるとかするとポリゴン数が不味い。



外部ツールによるリトポとの相性

ZBrushで試してみたい。まだ未調整。ToDo。



ツールごとの特性


cray:ブラシ形状に盛る/削る。大雑把な質量を作り出すときに一番効率がいい。

素早く振ると中間が消えてしまうのが困りもの。また、削ることで平面を作り出すのは、インターフェースの方向も相まって割と苦手。

ブラシサイズを調整しつつ大雑把な盛り付け/削りを行い、他のツールを使ってバランスを整える、というのがすごく速い。


inflate:球状に膨らませる/穴を開けるツール。

特定の面に対して、球っぽく盛り上げたり、表面を起点として削ったりができる。

積層された素材に対して綺麗に穴を開けたり、穴のフチの輪郭を、どの面を盛るかのバランス見ながらいじったりする時にメチャクチャ便利。

すでに形成されている稜線に対しての操作をする時に重宝する感じ。


smudge:浅く面的に盛るツール。

面に対して、不均一な感じに盛りができる。スムーズに近い機能として使える。

感覚としては篩(ふるい)を使って指向性を持たせてパウダーを盛っている感じ。

篩としての形状は円形なので、




ここからおまけ:Mediumでのモデリング最速化を考える

例えばZBrushとかだと身近に先駆者がいて、

その人に教えてもらうことで「こういうのが作りたい場合はこう作ると楽」みたいなのが聞けてよかった。


で、Mediumでもそういうのを探してみようと思う。



要件定義

・用途を持ったモデルを

・形状に対して

・サクッと作る


みたいな技術は、とにかく数をこなしたい時にとても良い。

イテレーション回数をあげてクオリティを出したい時に試みるといいこと、っていうのはMediumにもあると思ってる。



具体的にはどんな要素がありそうか

ここでは、「いい感じのバランスを作り出すために試行する」という言葉を縮めて「尺を取る」にしている。

ざっくり次のショートハンドがありそう。順は実行順を意図したものではない。

1.パーツ構成の尺を取る

2.全体/全身の尺を取る

3.ボリュームの尺を取る

4.カラーリングの尺を取る

1.パーツ構成の尺を取る

どんなツールを後続に使って何をするか、という部分に依存しそう。

自分の場合は「ゲームで使う」なので、モーションが入ったりいろいろする。

レイヤー分けとかが影響しそうなんだけど今の所ムクで一発パーツで作った場合と比べて何がベストなんだろ的な試行錯誤中。

ようは保留。



2.全体/全身の尺を取る

現在注力するとすぐ成果がでそうな分野。


特にMediumの場合、1レイヤー使って下書きみたいなのをやると良さそう。

・棒で長さの尺を取る

・何かでパーツごとの広さの尺を取る

とかで考えて見るか。

スタンプを使うことで記号化してバランス見るのを簡略化、みたいなのも答えかもしれない。



3.ボリュームの尺を取る

Mediumの場合、マスクみたいな概念が一切ないので、レイヤー分けが全てという感じになる。

例えば隣接したパーツが影響を受けてしまうので、そういうのはレイヤー分ける時にすでに織り込んでおかないと辛そう。


また、ユニット単位みたいなのに対してスナップ、っていう概念もないので、一度動かしたパーツを元の位置に戻すのもしんどい感じがする。

この辺はもうファジーなツールと割り切ってしまうのも手かもしれない(どうせズレる)


でもカチッとしたものを作りたい場合どうすればいいんだろう。



2016/12/14 時点での最適化

13.png

なんか怖いんだけど。10分くらいでこの辺まで行けるようになった。


・球をデカめに作ってシンメトリの中心に置く

・crayで輪郭線を書く

・埋める

・smudge, inflateを使って面を整える

みたいな行程でいくと、最大面積をガシガシ作りながら、狙った形状を作り出せることがわかった。

自分にとって特に難しかったのが鼻みたいな突起物を綺麗に作る方法だったんだけど、

その辺りはcrayで輪郭を作るのを徹底すると楽になった気がする。

crayで輪郭 -> 埋める のあたりは、でかいブラシ使ってガシガシやるようにしてる。

smudgeでの面の整い方には癖があるんで、もっと使わないとな。

inflateで稜線の処理ができるのがわかったのが収穫。これで、エッジさえ生成できればどんな図形でも綺麗に盛れそう。



wrote 2016/12/10 23:45:54

Unityのバッチビルド時にコンパイラディレクティブを渡す


概要

手段を探した。エディタ、プレイヤー両方あるいは片方で任意のものを外部から入力できねーかなーと思っていた。



公式ドキュメント曰く

Platform dependent compilation

https://docs.unity3d.com/Manual/PlatformDependentCompilation.html



末尾の方に各種rspファイルとその内容でのディレクティブの設定方法が書いてある。


で、gmcs.rspファイルを生成して、特定の記法でビルドに使われるフラグを定義できる。

さらにこれらの.rspはコマンドラインで実行する際にもちゃんと作用している。



試行錯誤

例えば下記のフラグをコマンドライン実行時に付与したい。

CLOUDBUILD

この場合、gmcs.rspファイルには下記を入れればいい。


gmcs.rsp

-define:CLOUDBUILD


のだけれど、例えばこのファイルを置きっぱなしにしてしまうと、ビルド時にずっとそのフラグがセットされた状態になってしまう。

それは嬉しくないので、

・内容を変更する(ファイルごと消すとか

ということを毎回ちゃんとやりたい。



しかもこのgmcs.rspを使った方法、割と癖があって、

・gmcs.rspの内容を変更しても、コンパイル対象のスクリプト自体に変更がないと、反映されない

のだった。マジか。


このフラグ周りについてコンパイル後に手をだすことはできない(そもそもコンパイル自体に影響するパラメータだこれ)ため、

次のような手段を用いてみた。


1.gmcs.rspファイルを生成する

2.gmcs.rspファイルに使いたいフラグを書き込む

3.trigger.csファイルを生成する

4.trigger.csファイルの中身をランダムかつ適当に用意する(秒まである日付とかがベスト

5.コマンドラインでUnityプロジェクトをビルド(-quitオプション付きで完了後に自動終了

6.gmcs.rspファイルとtrigger.csファイルを消す


こうすると、連続してコマンドラインビルドを行なった場合でも、常に最新の内容のgmcs.rspの内容のフラグを反映させることができる。


また、gmcs.rspファイルそれ自体が必要ない場合に対しても対応できる


(ただし既存のgmcs.rspファイルを消してしまうという害がある



実コードはこちら

こんな感じ。

# update defines.

echo -define:CLOUDBUILD > ./Assets/gmcs.rsp


# update date.

DATE=`date +%Y-%m-%d:%H:%M:%S`

echo //${DATE} > ./Assets/MiyamasuTestRunner/Editor/Timestamp.cs


# unity build.

/Applications/Unity/Unity.app/Contents/MacOS/Unity -batchmode -quit -projectPath $(pwd) -executeMethod Miyamasu.MiyamasuTestIgniter.CloudBuildTest


# delete.

rm ./Assets/gmcs.rsp

rm ./Assets/MiyamasuTestRunner/Editor/Timestamp.cs



とりあえずmiyamasuではこの方式を使って、手元で簡単にコンパイラディレクティブ渡してビルドしていろいろ試してる。




wrote 2016/12/09 14:17:50

Java、JDKをインストールせずに使ったり捨てたり


概要

ろくなアンインストーラが無い上にあなたとJavaインストーラは変な挙動するので本当にJavaインストールしたくない。

結論として、あなたとJavaを見ずにJavaをそのへんに入れたり捨てたりが容易にできるようになった。


なので正しい題としては、「あなたとJavaを見ずにJavaをそのへんのフォルダにインストールする」になる。



ある程度の経緯

ホストマシン(Mac)にJavaをインストールすると通知とか管理が本当にウザいので、

JDKをDocker側に入れてホストマシンからはそれを使うようにしたい。という感じで考えていた。

Dockerをつかってどうこうするのはまあよく考えたら無理で、代替を探していろいろやった話。

そのうちもっとちゃんと隔離したい。



今回の用途、Dockerだとなぜ適さなかったのか

Dockerの-vでのボリュームだと、

・Macの特定のフォルダ以下のパスを

・Dockerのコンテナの特定のフォルダに接続する


ということをしていて、まあ、想定されているアクセス方向としては


アクセス方向 -> 

Docker(

特定path -> 

Mac(

特定path

)

)


という、「DockerからMacの特定パスにアクセスできる」という機能なわけで、

今回自分が欲しかったのは下記。


アクセス方向 -> 

Mac(

特定path -> 

Docker(

特定path(ここにJava入れて云々)

)

)


で、まあ、これはDockerコンテナの仕事ではなく、ホストOSに対するパーティショニングみたいな概念で、

そもそもDockerじゃなくてもいいじゃんみたいな感じに落ち着いた。Javaまわりいろいろ多いので、できれば隔離したかった。


戦略としては、

・Macの特定フォルダ以下にJDKが入ったフォルダを置く

だけ。


まずJDKインストーラを分解します

できればOracleのサイトから何かDLするのすらやりたくなかったんだけど、

こればっかりはしょうがないのでOracleのサイトからJDKのインストーラをDLしてくる。

http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html



dmgしかない。ここにtarなどがあればここからの苦労は本当に必要ない。ちなみにJREはtarで配布されてる。なぜなの。



分解工程

まずはどこでもいいので、tmpフォルダを用意して、その中にJDKのインストーラを分解したものを出力

mkdir tmp

この状態で、DLしてきたJDKのdmgをダブルクリックし、/Volumeでアクセスできるようにする。

スクリーンショット 2016-12-05 19.59.28.png


デスクトップにこういうのが表示された状態で、packageutilを使ってインストーラの中身をtmp内に展開する。


cd tmp

pkgutil --expand  /Volumes/JDK\ 8\ Update\ 111/JDK\ 8\ Update\ 111.pkg ./jdkpkg


これで、JDKの中身がtmpフォルダに展開される。

スクリーンショット 2016-12-05 20.02.46.png

さらにpkgが出てきたので分解する。

javaappletまだ積んでるのか。そちらは要らないので無視する。


jdk180111.pkgを分解する。


なんでpkgからpkg出てくるんだろ?っていう疑念は当たりで、このpkgに対してpkgutilを使うと失敗する。

で、

これは拡張子はpkgなんだけどどうやらpkgではないという。なにしてんの。


いろいろ探してたら先駆者がいた。先駆者の人たちどんな気持ちでこのテクニックにたどり着いたんだろう。


How to install java 7 on mac in custom location?

http://stackoverflow.com/questions/15217200/how-to-install-java-7-on-mac-in-custom-location

というわけで、このpkgはこれ、pkgではなくGZipされたCPIOファイルだそうで。へぇ。なんで.pkgなんだ、、、


cpio -i < ./jdkpkg/jdk180111.pkg/Payload



やったぜ。

スクリーンショット 2016-12-05 20.40.41.png



無事javaがそのへんに置けましたね。よかったよかった。

これでおもしろインストーラを一切実行せずに、ホスト環境を汚されずに済む。そして捨てやすい。



使い方

いちいち下記をやってもいいし、

export JAVA_HOME=どこか/tmp/Contents/Home/


bashrcとかをいじってもいいと思う。

自分は必要な時だけ必要なので、これでいい。



動くの?

動くよ。

スクリーンショット 2016-12-05 21.14.00.png



注意点

extractしたHomeディレクトリの奥深くに、Java Mission Control.appというAppが入っているので、

使わない場合は消せばいいと思う。

スクリーンショット 2016-12-14 3.43.35.png

自分は存在に気づかなかったが確かにあって、用途を鑑みるにろくでもないものをインストールしそうだったので消した。


wrote 2016/12/04 16:44:13

やすべえアドベントカレンダー2016


概要

こちら。

http://www.adventar.org/calendars/1349



店舗

渋谷店の厳選した(==httpsである)リンクはこれら。

https://tabelog.com/tokyo/A1303/A130301/13001149/

https://ramendb.supleks.jp/s/2.html

https://www.hotpepper.jp/strJ000244786/

x https://r.gnavi.co.jp/1k1sdneg0000/



内容

あつもり、他



ビジュアル

before

IMG_2406.JPG



after

IMG_2407.JPG



zoom

IMG_2409.JPG




wrote 2016/12/03 19:43:12

RFCに準拠したHTTPヘッダ比較について


概要

RFCに反してるライブラリ使ってハマってた。



何が起こったか

httpのヘッダのキーに大文字小文字でフル一致できる文字列が入っているはず、という

謎の期待をするクライアント実装があって、

それを知らずに使っていたため通信結果が失敗に終わるという感じで、なかなか真相に気づかずにハマった。


対象のライブラリはこちら。


websocket-sharp

https://github.com/sta/websocket-sharp



困ってた部分のコードはこんな感じになっている。


WebSocket.cs

https://github.com/sta/websocket-sharp/blob/ad563fa46c688094048fe3ed7a1df292e7bbe5d3/websocket-sharp/WebSocket.cs#L779

      var headers = response.Headers;

      if (!validateSecWebSocketAcceptHeader (headers["Sec-WebSocket-Accept"])) {

        message = "Includes no Sec-WebSocket-Accept header, or it has an invalid value.";

        return false;

      }


      if (!validateSecWebSocketProtocolServerHeader (headers["Sec-WebSocket-Protocol"])) {

        message = "Includes no Sec-WebSocket-Protocol header, or it has an invalid value.";

        return false;

      }


      if (!validateSecWebSocketExtensionsServerHeader (headers["Sec-WebSocket-Extensions"])) {

        message = "Includes an invalid Sec-WebSocket-Extensions header.";

        return false;

      }


      if (!validateSecWebSocketVersionServerHeader (headers["Sec-WebSocket-Version"])) {

        message = "Includes an invalid Sec-WebSocket-Version header.";

        return false;

      }


この内容と大文字小文字がジャストマッチしてないと、WebSocket接続のハンドシェイクが失敗に終わる。



対して、WebSocketのRFCの基準はこちら

https://tools.ietf.org/html/rfc6455#section-2.1


Comparing two strings in an _ASCII case-insensitive_ manner means

   comparing them exactly, code point for code point, except that the

   characters in the range U+0041 to U+005A (i.e., LATIN CAPITAL LETTER

   A to LATIN CAPITAL LETTER Z) and the corresponding characters in the

   range U+0061 to U+007A (i.e., LATIN SMALL LETTER A to LATIN SMALL

   LETTER Z) are considered to also match.


文字列比較について、特に_ASCII case-insensitive_って書いてあるところはこうすべきだよ~みたいな但し書きがあって、

・大文字だろうが小文字だろうがマッチすること

という感じになっている。



というわけで、修正したものをプルリク済み。

https://github.com/sta/websocket-sharp/pull/315



ちなみに一切テストコードが存在しないんで、まあ、なんだ、、一度手元で動かしたけど確証はないので、つらい。



wrote 2016/11/28 1:19:53

JWTについての学び


概要

この辺見て勉強する。

https://jwt.io/introduction/


RFC 7519

https://tools.ietf.org/html/rfc7519



なんのためのものなのか

Auth、InformationExchange とある。

https://jwt.io/introduction/


構成要素

header, payload, signatureの三つ。

すべてオリジナルはJSON形式。実際の値になるときには暗号化されたりしている。



header

typeとアルゴリズムの指定記述が入る。

type(キーはtyp)にはJWT、アルゴリズム指定(キーはalg)にはアルゴリズムの種類が入る。

{

  "alg": "HS256",

  "typ": "JWT"

}


この値はBase64エンコードされる。

payload

エンティティ。claimsというパラメータを含む。

claimsは3タイプに分かれる。

Reserved, Public, Private


Reserved

JWTで定義されている定義済みのclaims。

例えばiss(issuer)、exp(expiration time)、sub(subject) とか。

3文字。このへんからコンパクトにしたいらしい。


Public

IANA JSON Web Token Registryとかの定義されてるもの。

https://www.iana.org/assignments/jwt/jwt.xhtml


Private 

カスタム。公には共有せず、サービス内とかで共有すべきもの。


payloadのサンプルはこんな感じ。

{

  "sub": "1234567890",

  "name": "John Doe",

  "admin": true

}

これもBase64エンコードされる。


signature

作成するにはエンコードされたheaderとpayloadとシークレット、

headerに記述されたアルゴリズムが必要で、それらを使ってsignしたものがsignatureになる。


具体例としてHMACSHA256を使ってsignatureを作るコードは次のような感じになる。

HMACSHA256(

  base64UrlEncode(header) + "." +

  base64UrlEncode(payload),

  secret)


ふむふむ。headerをエンコードしたもの + “.” + payloadをエンコードしたものを、secretをキーに使ってHMACSHA256にかければいいと。


こうして作成されたsignatureは、経路でデータ改ざんがされなかったことの保証や、誰がこのデータ(JWT)の発行者かなどを保証するために使われる。


で、ここまでの成果物は、次の通りになる。


header(encoded)

payload(encoded)

secret

signature


で、これらを次の形でつなげる。

header(encoded) + ”.” + payload(encoded) + “.” + signature


ふむふむ

・headerに書いてあるアルゴリズムとsecretを事前に知らなければ復号できない

という感じか。


動作について

ユーザーが持っていたcredentialでログインできたら、サーバーはJWTをユーザーに渡す。

ユーザーはサーバーにアクセスする際、AuthorizationヘッダにJWTを乗せる必要がある。


その際Bearerスキーマでセットして送る。

Authorization: Bearer <token>


こうするとサーバーのメモリ上にも一切ユーザー関連のデータが残らないのでステートレスにできるよねっていう話。


JWTの利点

SimpleWebToken(SWT), SAML(Security Assertion Markup Language)と比較してる。


JSONはXMLより簡潔なので、エンコードされたサイズも小さい。

で、まあ、SAMLより小さい。これはHTTPとかでデータをやり取りするのに適してると思う。


セキュリティの観点で、SWTは対称暗号でのHMACしか選べない。

でもJWTやSAMLでは公開暗号がsigningに使える(X509)。

その上で、JSON使ってやったほうが楽だよねみたいな。


JSONパーサはこの世にいっぱいあるんでXML(要はSAML)よりいいよねみたいな話。



Auth0について

オースゼロ、っていう会社かこれ。

なんかAPIを提供するのを商売にしてるっぽい。


横道、認証と認可について

http://dev.classmethod.jp/security/authentication-and-authorization/


認証=Authentication:誰かを確かめること

例:adminなのかどうか判断する


認可=Authorization:権限、許可を与えること

例:切符を持っているので電車に乗っていい



実用例

https://www.toptal.com/web/cookie-free-authentication-with-json-web-tokens-an-example-in-laravel-and-angularjs


ネームスペースはIANAに登録があるよ

https://www.iana.org/assignments/jwt/jwt.xhtml


このへんから漁ってほしいものをPayloadの中身のキーとして使うと良いよって話。


wrote 2016/11/25 2:16:17

Unity用軽量WebSocketライブラリ WebuSocket、TLS対応するとかそのへん完了


概要

Unity用の小さなWebSocketクライアントのメンテをちょっとやってた。

TLS1.2まで対応済み。TLSはBouncyCastleに依存。レアな利用例コードが見れるぞ。


WebuSocket

https://github.com/sassembla/WebuSocket



特徴

このライブラリ自体は一切スレッドを作成してないので、ものすごい負荷をかけても電池の消費が少ない。

対比としてはWebSocketSharpの半分くらい。


メモリ消費も少なめで、TLS対応のためにどうしてもバッファのコピーが1度だけ必要なの以外はかなりメモリ消費しない。


そしてコードサイズが小さめ。リファクタしようと思う部分は多々あるんだけど。


これから

旧バージョンで書いていたテストコードをリファクタリングして行く予定。

あと、UnityがC#6 DotNET FW4.6対応しても、たぶんパフォーマンスで勝負できそうな気がしている。


同様の設計基軸でQUICのほうも用意中なので、そのうち公開できればと思う。




wrote 2016/11/22 23:55:43

AssetBundleGraph


概要

Unibook総集編でAssetBundle使った運用の話(2012のやつ)をアップデートしたのが載る。

間に合えば。


で、この項ではAssetBundleGraphを使って簡単なAssetBundleを作る例を用意しようと思う。



というわけで用意しました。

http://sassembla.github.io/Public/2016:12:23%2000-00-00/2016:12:23%2000-00-00.html

ご笑覧ください。



たぶん世界で唯一、AssetBundleGraphの使用例がまとまっているサイトになる。



wrote 2016/11/17 2:18:34

しっぴつのためにRe:VIEW環境をmacOS sierraに構築


概要

最新(2016/06時点)でのインストール用の書類がこちら

書籍執筆用の仕組み「Re:VIEW」の環境構築とRe:VIEW記法の紹介

http://magicbullet.hatenablog.jp/entry/review_howtouse

多分同様のものだと思うんだけど、vvakame氏がDocker imageにしてくれてた。

vvakame/review

https://hub.docker.com/r/vvakame/review/



いいところ

特定ボリュームを編集スペースにしたりできる。

そういうの期待してたんですごくいい。


wrote 2016/11/15 12:39:54

MuroAnime行ってた


概要

これ。

https://eventdots.jp/event/599488


どうやって作ったか、どういう構成要素になってて、このエフェクトの狙いは?とか とても細かく聞ける会だった。



ミクさん奴

Qiitaに上がってる

http://qiita.com/MuRo_CG/items/c417ef6d6cbeed3dd42b



テクスチャの調整

頑張って階調落とす

胸とかの線は描いてた



ライティングの調整

光源を意識する。固定光源

顔と体とか、かなり細かくライトを分けてる。



ImageEffectを使ってみる

フレア、ディフュージョン(ブルーム)とかよく使う。

3Dは絵が固くなりやすい=エッジが強く出るので、それをブルームでぼかすとかそのへん。



フレア

画面前に板ポリ置く



アンチエイリアス

QualitySettingでFantasic指定してアンチエイリアシング強くしてる。

トゥーンの場合は元絵の時点でアンチかけておかないといけなかった。

ポストエフェクトだとジャギッた絵にアンチがかかる。



Bloom二回入れてる

発光、ぼかしの2段階にしてる


まとめて出来ない?

->背景の光と、キャラクターの輪郭線とかに出るような光を一緒くたにつくれなかった


白黒化してバランスを見る

カラースケール フィルタ



24fps

アニメ準拠。



手前にミク、遠景のビル

偽ビル

遠景、超大量のビル

グレースケールのノイズテクスチャをパーリンとかで作って、そいつをTerrainとして読み込んで立体化


偽ライト

ビル群の隙間から光が出る

-> それっぽいフレア用のテクスチャ置いてる



10年代っぽい回転しながら落下奴

kode80さんの雲を生成する奴とか使ってた。

http://kode80.com/blog/



色味とかシーンの組み立て

夕日にはいろんな色が含まれるよねっていう感じでColorScaleとかで調節

雲に紫色


キャラクターの姿勢とかは別の方向からみるのを度外視した仰け反り

別にこっちからしか映らないし、、



参考にしたりしてる資料の話


MSC

http://msc-jp.biz



アニメ用語集

http://msc-jp.biz/material_html/terms_A.html

まとまっていてとてもいい。



撮影虎之穴

GAINAXのウェブページでグレンラガンのエフェクトの解説がいっぱいあったらしい。


インターネットアーカイブにはある。


最終回あたりの解説リンクがこれ。

https://web.archive.org/web/20151108140630/http://www.gainax.co.jp/anime/gurren-lagann/tora.html


2016/3月にはもうなくなってしまっていたらしい。



水たまりのアレとか

AssetStoreのUBER shader

https://www.assetstore.unity3d.com/jp/#!/content/39959



Q&A

キャプチャってどうやってるんです?

-> ShadowPlay

http://www.nvidia.co.jp/object/geforce-experience-shadow-play-jp.html


wrote 2016/10/23 22:34:05

wasm使って遊ぶ


概要

UnityでWebAssemblyを使って遊ぶ



wasmって何

https://blogs.unity3d.com/jp/2015/06/18/webgl-webassembly-and-feature-roadmap/


https://github.com/WebAssembly/design/blob/master/FAQ.md

JSを置き換えるもの? -> No。

、、、って言ってるけど、

まあ、JavaScriptのライブラリとかを作り上げるためのバイナリ、みたいな感じ。


何ができるようになるの?



実行面

・高速な読み込み

DLが終わってからのブラウザの読み込みが高速。

jsの倍くらい。

実行速度は一緒。


・軽量

jsそれ自体よりもサイズが小さくなる。3/4 ~ 1/2程度。

つまりjsより高速にDLされる。



制作面

・ライブラリ配布に適している

いままでのjsが手に入れられなかった「JSでは無い、jsで使えるオフィシャルな資産」

・コンパイルできるようになる

コンパイラを通すので、jsでありながら、事前にコンパイルができるようになる。

これはwasmの機能っていうよりは、開発環境の話。


まとめると、

jsの3/4程度のサイズ -> DLが1.2倍くらい高速

jsより倍くらい早い読み込み -> 2倍くらい高速なロード時間



実践WebAssembly with Unity5.5(beta7)

コンパイル

スクリーンショット 2016-10-17 18.29.16.png

スクリーンショット 2016-10-17 18.31.18.png



一番下のWebAssembly のチェックを付けるだけ。

付けるだけで、


Unityで作ったコンテンツがブラウザで動くようになる。



簡単なjsとの比較

jsでのUnityのコンテンツ:

2,705,128 byte = 2.7MB。

スクリーンショット 2016-10-17 18.38.53.png


wasmでのUnityのコンテンツ:

1,777,359 byte = 1.8MB。

スクリーンショット 2016-10-17 18.37.55.png

、、、軽い!!!(確信


比較すると、wasmはjsと比べて、65%ほどのサイズになった。



この拡張子(wasmgz)ってなんなの?

gzip圧縮ってのやっててね、ブラウザにDLされると展開されるんだよ。



動かしてみたい、、、動かしてみたくない、、?

こんな感じにサイズが減るぞWebAsm!!


サイズが小さくなってDLが速くなって、読み込みも高速なそんなWebAsm!!


で!?


実際のブラウザで使えんの??



そんなときはこのサイト! 


Can I Use..

http://caniuse.com/#search=was

スクリーンショット 2016-10-17 18.50.10.png


旗がついてるブラウザで使える。

旗がついてるブラウザでメニアックな設定を変えると使える


Safari、iOS Safari、Android Browser ともに全滅。

Firefox、Chrome、Chrome for Androidでは条件付きで動く!


IE、Edgeでは、まだ。

ほか、、、のはまああってもなくても変わらんでしょ。(Operaは買収されて鬼籍に入ったんで考えない


ちなみに、

スクリーンショット 2016-10-17 18.58.35.png


全ブラウザ、正式対応はまだだけど、In Development (開発中) なんだね。


UnityでのWebコンテンツについて

ちょっと毛色を変えて、UnityでWebコンテンツを作ることができるのか?


-> できる。

-> できるのだ。



この記事を書いている人はこんなライブラリを作っています


Unidon

https://github.com/sassembla/Unidon


こいつは、Unityのコンテンツをhtmlページっぽい概念で切り分けて、分割してロードして実行可能にする、っていうやつ。



Unity + WebAsmでビルドしたコンテンツをブラウザで実行してみる

WebAsmに対応してないブラウザの場合:


MacSafari上で動かすとこんな感じにフォールバックが発生して、asm.jsのバージョンのほうが使用される。

スクリーンショット 2016-10-17 19.20.14.png


WebAsmに対応してるブラウザの場合:

ローディングが開始されて表示されるまでが「きもち」短い。



仕上げていくよという感じ。

wrote 2016/10/17 17:59:14

過去のバージョンのVSCodeをDLする


概要

1.6.x系になってから、どうやらコンパイルエラーが3秒で消えるようになってたらしい。

Unityのコードをひたすらゴリゴリ書いてたので気づかなかったんだけど、1.6.1が配信されだしてから異変に気づいた。



症状

コンパイルエラーがあるじゃろ

ha.png

3秒まつじゃろ


oh.png

エラー表示が消える


エラー件数も0件になる


コエーー

(この画像は今手元に唯一残ってる1.5.0の画像を編集して再現したでっちあげなんで、もしかしたら1.6.0とは細部デザインが違うかも)



対処法

古いのDLしよ? サイズも50M程度だし。


下記からDLできた。XとかYに欲しいバージョンの数字を入れよう。

https://vscode-update.azurewebsites.net/1.X.Y/darwin/stable


っていいつつまあ最新使わないのは本当に色んな意味でよくないので、1.6.2が出たら起こして。


wrote 2016/10/14 15:59:21

Docker Autobahn環境 + wss + BouncyCastle C#


概要

これ

http://autobahn.ws


が動く環境をDockerで作って、適当に動かす。主にTls周りとか。

C#側はWebSocket(生ソケットで遊ぼうの会) + BouncyCastle解読回。


DockerでのAutobahn動作環境の作成から、C#でのBouncyCastleの使い方発掘、TLS通してHandshakeまでをやる羽目になった。



動機

自作のC# WebSocketライブラリ「WebuSocket」で、WebSocketのテストちゃんと通したことそういえば無いよねっていう感じ。



準備

docker pull python

これで入る環境ってどんなのなんだろう。Python3だと嬉しいんだけど。

-> 3.5だった。やったね!


container立ち上げて

docker run -ti -d --name python python:latest



bash起動して入る

docker exec -ti python bash



Autobahn動かす

TLSで動くサンプルがあるんで、これが動かせれば行けそう。

適当にソースをホストに置いて、動かせるようにしてみよう。


docker run -ti -d --name python -v /Users/tartetatin/Desktop/pythonServer:/usr/local/src python:latest

Autobahnの備え付けのサーバを動かすために、いろいろ依存が足りないので入れる。

pip install autobahn

pip install twisted

pip install pyopenssl

pip install txaio

pip install service_identity



まだport開けてなかった、、一度イメージに落とすのがいいのかな、、commitしちゃおう、、

docker commit python autobahn:latest



というわけで、ホストから接続


docker run -ti -p 8000:8000 -p 9000:9000 -d --name autobahn -v /Users/tartetatin/Desktop/pythonServer:/usr/local/src autobahn:latest


8000番はHTTP、9000番はWebSocketの受け口にしてる。

で、

ブラウザで8000番を開くと、certificate入れなよ~っていうリンクを示してくれる。

スクリーンショット 2016-10-13 15.10.14.png


そのままブラウザで9000番を開くと、ここはWebSocketのEndPointだよ~って言われる。

スクリーンショット 2016-10-13 15.10.21.png

で。

ブラウザで適当なWebSocketクライアント書いて接続をwss://127.0.0.1:9000で行うと、 OSStatus Error -9807: Invalid certificate chain が出る。 ふむ。まあ確かに。オレオレ証明書だし。


ブラウザを説得するのは諦めて、C#のSocketでの接続を考える。

ここで問題にぶち当たる。



SslStreamを使えばTLSでAutobahnとの接続はできるんだけど、これTLS1.0じゃん。あとSslStreamねぇ、、、

C#というか。.Net FrameworkにはSslStreamという、SSL系の動作をhandshakeからsend/receiveまでまるっと飲み込んだAPIが存在する。

存在するんだけどさ~~~。必ずNetworkStreamを使う実装になっちゃう。

で、作ってるWebuSocketっていうWebSocketクライアントは、Socketを使っていろいろやってるので、NetworkStreamに落ちたら負けだと思って(ry


SocketからNetworkStreamを取り出してSslStreamに繋ぐ、とかはまあ、超簡単にできるんだけど、StreamのAPIが気に食わん。

非同期API使うに決まってるんだけど、Task使うんで必ずThreadできちゃうし。


Socketでなんとかしたいな~ってなって、いろんな方向を探した。


ぶっちゃけやりたいこと

・TLS protocolでのサーバとのやりとりは、ざっくり言うとそういう動作をする state machine が手にはいればよい。

・インターフェースとして、TCPで取得したbyte[]を放り込むと、TLSのhandshakeをしたり、handshake済みであればdecryptedなbyte[]を吐き出す機構がある、、はず


で、探したら.Net Frameworkにはそういうのなかった。


困ったことに、.Net Frameworkには、TLSを扱えるstate machine が無い。

JavaでいうSSLEngineみたいなやつ。

なんでねーーーんだろう。SslStreamでみんな満足してんの? 本当?

で、いろいろ探し回って、OpenSSLのC#ラッパ見たり、オープンソースな何かとか見てて、

最終的にBouncyCastleにたどり着いた。


そんなBouncyCastle

https://www.bouncycastle.org/csharp/index.html


github上にもある。

https://github.com/bcgit/bc-csharp



、、、信じられないことにAPI documentが無いんだよね。なぜだろうね。

testとか読むことになった。



というわけでBouncyCastleを読む

まずは関係ありそうなTlsTestCase.csを見てみる。

https://github.com/bcgit/bc-csharp/blob/master/crypto/test/src/crypto/tls/test/TlsTestCase.cs



いろいろあるな~~楽しそうなの。

WriteHandshakeMessage


blockingモードでのみ使えるStreamとか


public virtual void OfferInput(byte[] input) こっちはノンブロッキング前提でしか使えないらしい。データを送るっぽい。

public virtual void OfferOutput(byte[] buffer, int offset, int length) データを受け取るっぽい。



-> streamを引数に持つTlsClientProtocolコンストラクタは全部ブロッキングで、

SecureRandomだけを引数に持つTlsClientProtocolコンストラクタがノンブロッキングだった。


-> そもそもブロッキングモードってなんなの?

あとでわかることだが、streamを使った入出力隠蔽ができているものをblocking、 

streamを使わず自分でbyte[]入れたり出したりできるstate machineとしての利用法のことをnon-blocking と呼んでいるようだった。


それはblockingという概念だろうか、、、



どうやら、俺が欲しいものはnon-blocking modeらしい。



これとりあえずどうやってip/port指定するんだろう。

-> byte[]でのインプット、アウトプットを与えると、内部状態が勝手に遷移するっていうスーパートンチキマシンだこれ。

、、たのむドキュメントに書いててくれ。最高だぞこの機能。っていうかなんでC#オリジナルには存在しないんだよこういうの。

(SslStreamはstreamになっちゃうのでこの辺隠蔽できてるんだけど、隠蔽しすぎててsocketと併用できない。



test codeから使い方を読み解く

この辺のコードが参考になっ、、たらよかったんだけど。

このコードでしかnon-blocking mode が出てきてなかったので、これしか参考になるものがなかったと言ったほうがいい。

https://github.com/bcgit/bc-csharp/blob/master/crypto/test/src/crypto/tls/test/TlsProtocolNonBlockingTest.cs



BouncyCastleのAPIを使ったサンプル

C#のSocketでの接続から送受信まで、まとめて書く。

本当にわかりにくいAPIだった。こういうテストかドキュメントがあればめっちゃ簡単に済んだ。


クライアント側のコードで、Socketを使ってサーバに接続、TLSでのnegoとかして、TLS handshakeが終わるところまでのサンプルが下記。

おまけで、handshake後にデータの送受信をしている。


セキュリティ的にはガバガバなので、まんま使って死なないように気をつけてね。



クライアント側の前提

・DefaultTlsClientを拡張したMyTlsClientクラスを定義してある。(独自のTlsAuthenticationを返すメソッドを実装する必要があるので定義必須)

・MyTlsClient内に、MyTlsAuthenticationクラスを定義してある。(TlsAuthenticationがabstractなので実装必須)


サーバ側の前提

・ここでテストに使ったサーバは、TLS1.2が喋れるサーバ。

・サーバは、handshakeが終わった後にクライアントから送られてきたデータがあれば、そのままクライアントに返すという仕様。


using Org.BouncyCastle.Crypto.Tls;

using Org.BouncyCastle.Security;

using Org.BouncyCastle.Utilities;

using System;

using System.Collections.Generic;

using System.Net;

using System.Net.Sockets;

using System.Text;


public class MyTlsClient : DefaultTlsClient {

internal TlsSession mSession;


internal WebuSocketTlsClient (TlsSession session) {

this.mSession = session;

}


public override TlsSession GetSessionToResume () {

return this.mSession;

}


public override void NotifyAlertRaised (byte alertLevel, byte alertDescription, string message, Exception cause) {

Debug.LogError("TLS client raised alert: " + AlertLevel.GetText(alertLevel) + ", " + AlertDescription.GetText(alertDescription));

if (message != null) {

Debug.LogError("> " + message);

}

if (cause != null) {

Debug.LogError(cause);

}

}


public override void NotifyAlertReceived (byte alertLevel, byte alertDescription) {

Debug.LogError("TLS client received alert: " + AlertLevel.GetText(alertLevel) + ", " + AlertDescription.GetText(alertDescription));

}


public override void NotifyServerVersion (ProtocolVersion serverVersion) {

base.NotifyServerVersion(serverVersion);

// Debug.LogError("TLS client negotiated " + serverVersion);

}


public override TlsAuthentication GetAuthentication () {

return new MyTlsAuthentication(mContext);

}



private class MyTlsAuthentication : TlsAuthentication {

private readonly TlsContext mContext;


internal WebuSocketTlsAuthentication (TlsContext context) {

this.mContext = context;

}


public void NotifyServerCertificate (Certificate serverCertificate) {

// X509CertificateStructure[] chain = serverCertificate.GetCertificateList();

// Console.WriteLine("TLS client received server certificate chain of length " + chain.Length);

// for (int i = 0; i != chain.Length; i++) {

// X509CertificateStructure entry = chain[i];

// // TODO Create fingerprint based on certificate signature algorithm digest

// Console.WriteLine("    fingerprint:SHA-256 " + TlsTestUtilities.Fingerprint(entry) + " (" + entry.Subject + ")");

// }

// なんもしてない。certが正しいかどうか、チェックしないといけないはず。

}


public TlsCredentials GetClientCredentials (CertificateRequest certificateRequest) {

byte[] certificateTypes = certificateRequest.CertificateTypes;

if (certificateTypes == null || !Arrays.Contains(certificateTypes, ClientCertificateType.rsa_sign)) {

return null;

}


// return TlsTestUtilities.LoadSignerCredentials(mContext, certificateRequest.SupportedSignatureAlgorithms, SignatureAlgorithm.rsa, "x509-client.pem", "x509-client-key.pem");

return null;

}

}


public override void NotifyHandshakeComplete () {

base.NotifyHandshakeComplete();


TlsSession newSession = mContext.ResumableSession;

if (newSession != null) {

// byte[] newSessionID = newSession.SessionID;

// string hex = Hex.ToHexString(newSessionID);


// if (this.mSession != null && Arrays.AreEqual(this.mSession.SessionID, newSessionID)) {

// Debug.LogError("Resumed session: " + hex);

// } else {

// Debug.LogError("Established session: " + hex);

// }


this.mSession = newSession;

}


Debug.LogError("handshake終わった、このへんが非同期に呼ばれるっぽいので、WebSocketのhandshakeを呼ぶきっかけにできるかもしれない。");

}

}



// client connection starts from here.


var endPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 9000);


var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);


// connect socket to server peer.

socket.Connect(endPoint.Address, endPoint.Port);


/*

ready for tls handshake.


tlsClientProtocol contans the state machine,

which can generate "byte[] data" for negotiating TSL protocol with server.

*/

var tlsClientProtocol = new TlsClientProtocol(new SecureRandom());


// "Connect" means not connect to server. connect means initalize tlsClientProtocol in non-blocking mode.

tlsClientProtocol.Connect(new MyTlsClient(null));


// first, send ClientHello to server.

{

// get ClientHello byte data from tlsClientProtocol instance and send it to server.

var buffer = new byte[tlsClientProtocol.GetAvailableOutputBytes()];

tlsClientProtocol.ReadOutput(buffer, 0, buffer.Length);


// send it to server through socket.

socket.Send(buffer);

}


// wait response data from server.

{

while (socket.Available == 0) {}

var available = socket.Available; 

var responseFromServer = new byte[available];

socket.Receive(responseFromServer);

// set received data to tlsClientProtocol by "OfferInput" method.

// tls handshake phase will progress.

tlsClientProtocol.OfferInput(responseFromServer);


// and next handshake data can be get from tlsClientProtocol.

var buffer = new byte[tlsClientProtocol.GetAvailableOutputBytes()];

tlsClientProtocol.ReadOutput(buffer, 0, buffer.Length);


// send it to server.

socket.Send(buffer);

}


// wait response data from server.

{

while (socket.Available == 0) {}

var available = socket.Available;

var assumedBuffer = new byte[available];

socket.Receive(assumedBuffer);


// set received data to tlsClientProtocol by "OfferInput" method.

// tls handshake phase will become completed! in this client side. 

tlsClientProtocol.OfferInput(assumedBuffer);


// send ClientFinish data to server.

var buffer = new byte[tlsClientProtocol.GetAvailableOutputBytes()];

tlsClientProtocol.ReadOutput(buffer, 0, buffer.Length);

socket.Send(buffer);

}


// tls session is established! yay!!


// sending data.

{

var helloString = "hello, tls.";

var helloBytes = Encoding.UTF8.GetBytes(helloString);


tlsClientProtocol.OfferOutput(helloBytes, 0, helloBytes.Length);


var count = tlsClientProtocol.GetAvailableOutputBytes();

var buffer = new byte[count];

tlsClientProtocol.ReadOutput(buffer, 0, buffer.Length);


socket.Send(buffer);

}


// receiving data.

// assume that server returns client sended data like echo.

{

while (socket.Available == 0) {}

var available = socket.Available;


var receiveBuffer = new byte[available];

socket.Receive(receiveBuffer);


tlsClientProtocol.OfferInput(receiveBuffer);


var len = tlsClientProtocol.GetAvailableInputBytes();

var receivedDecryptedBytes = new byte[len];

tlsClientProtocol.ReadInput(receivedDecryptedBytes, 0, receivedDecryptedBytes.Length);

Debug.LogError("server returned:" + Encoding.UTF8.GetString(receivedDecryptedBytes));

}


というわけで使い方がわかったので、WebSocketのHandShakeまで完成

で、WebuSocketでは不完全なデータが来た場合、それを破棄したい。

不完全なデータ = 途中で途切れて送られてくるデータ。

WebuSocketでは、すでにC#のSocketArgsのバッファがあるので、そのバッファにデータを溜めたまま、

データ全体がWebSocketのframeとして読めるようになるまで読み出さないという戦略を取っている。


で、これと、bcのTlsProtocolの実装との相性が悪い。

tlsProtocol、内部で完全にデータをコピーして動いている。

データを読み込ませると、それはinputStreamに突っ込まれる。で、中途半端なデータが来た場合、TLSの復号に失敗し、データは内部に残る。

bcとしては、そこに新しいデータを足すだけで動くようにしたいらしい。


で、WebuSocketとしてはそのキャッシュ機構が邪魔で、そいつを破棄したい。できるのかな~~


サイズが0になったら、WebSocketのフレームも不足しているものとして扱うことはできる。

すでに入っているものを消せるか?

-> inputStreamのSkipがその用途に使えそうだけど、これうーーーんん、、、どこからも叩かれてる形跡が無い。


BouncyCastleを変更するの避けたいな、、、Discardとかもなさそうだしな、、


-> リセットを実装するの簡単だった。

内部に用意してあったinput用のstreamに対して、ClientTlsProtocolを継承することで追加したメソッドからinputStream.Skip(N)を呼ぶことで対処できた。


で、次の戦略が成立する。


1.長さが足りないデータが来た場合、TLSProtocolを通すと、available = 0が返ってくる

2.availableが0の場合、そのデータはTLS的にダメなんで、WebSocketのframeとしても認めないことにする。

-> tls inputをリセットした上で、再度データが来るのを待つ。


3.availableが0でないデータの場合、TLS的にはOKなんで、復号できたデータをws frameとして展開しようとする。

4.wsのframe展開に失敗した場合、展開成功するまでデータはバッファに残った状態になる。

-> tls inputをリセットする必要は無いはず。次来たデータについての処理は、1から実行されるので。


本当は、bcの中でキャッシュするのもやめさせたい。どこまで読んだかっていうインデックスを操れるといいんだけど。

内部に一度コピーが走っちゃうのは本当に辛いな~~~~~~~~~


-> このへんも書き換えられそう。いいね!!



教訓

むやみにinternalを使いまくらないというBouncyCastleの人らの方針のおかげで欲しいもの作れた。

なんでドキュメントがないんだろう。悲しい。


あと、なんでbyteを吐き出すようなTls state machine がC#標準に無いの?

SslStreamだけで満足なの?


、、という疑問は誰かあの、、ぜひ、、教えてください、、、


Task使わずにそれらをコントロールできるAPIがスッゲー貧弱なんで、thread一切作らずパフォーマンス欲しい時に辛かった。


thread一つも作らずに済ませられるならそっちのほうがよくない?





wrote 2016/10/12 21:31:16

DockerでLaravel動かす


概要

まずToDoをまとめると、

・Docker入れる

・適当にphpとMySQLのimage用意する

・それらのコンテナ起動

・phpコンテナにLaravel入れる

・適当なLarabelプロジェクト作る

・アクセス


参考。

http://qiita.com/kukimo/items/c044ad42fffac062e2f5

絶対に絶対にPHP書きたくないがなんか特定の認証について知りたいのでやってみる。



Lamp環境入れる

docker run -p 80:80 --name php -d php:5.6-apache

こんな感じで。

Apacheっていうのが気にくわんがまあいいや。


起動しているプロセスの情報は、docker ps -a で確認できる。


Docker内のフォルダをhostとshareする

できるっぽいな?

っていうかそれできないと辛くてな。

-> exec コマンドがあるおかげで、なんか楽になってるっぽいぞ。ふむ?

http://stackoverflow.com/questions/25446055/how-to-edit-a-file-dynamically-in-a-running-docker-container?noredirect=1&lq=1

-> Dockerから手元のフォルダを指す方法があった。これでいいな、、、

手元に適当なフォルダを作り、

 /Users/tartetatin/Desktop/LaravelServer


docker run で、コンテナ内の特定のパスを、ホストの特定のパスと接続する。

docker run -p 80:80 -v /Users/tartetatin/Desktop/LaravelServer:/var/www/html --name php -d php:5.6-apache

これで、/var/www/htmlはapacheのデフォルトのドキュメントルートなので、ホストからDockerへのhttpリクエスト時に手元のフォルダが差されるようになった。

楽ジャーーーーン。



ホスト<->コンテナ間のファイルコピー

http://qiita.com/gologo13/items/7e4e404af80377b48fd5

双方向でできるようになってた。

わーーーい!!



コンテナを起動する

nameがかぶるんで、古いやつを適当に消さないといけない感じがする。

nameの概念を忘れた。なんだっけ、、


name -> imageから作成されたcontainerにつけられてるid。

containerはimageから生成され、起動中/終了中 などの状態を持っているので、nameで個々を区別する。


docker start name


で、すでに作成されたコンテナを起動できる。


docker run -> imageからcontainerを作る

docer start/stop container -> containerを起動したり停めたり

containerを指定するには、nameをつけておくといいよねっていう感じ。



作成したコンテナにTerminalで入る

docker exec -ti mysql bash

なんかかなり楽になってない? いいね~~



Dockerfile作ってPHPの入ってるコンテナを作り直す

適当なパスにDockerfile作る。


touch /Users/tartetatin/Desktop/LaravelServer/Dockerfile


Dockerfile

FROM php:5.6-apache

RUN apt-get update && docker-php-ext-install pdo_mysql mysqli mbstring


zip入れてcomposer入れてcomposerを移動してる。


それを元に、新たにPHPコンテナ立ち上げ。


docker build -t php:custom /Users/tartetatin/Desktop/LaravelServer/

なるほどな~~これで特定のimageをもとに、特定の構成で立ち上げられるimageが作成される。



MySQLの言語設定をUTF-8にして立ち上げる

なんか世知辛い事情によって、MySQLの文字コードはデフォルトではLatinらしい。

で、/Users/tartetatin/Desktop/LaravelServer/mysql/conf.dを作っておいて、MySQLの起動時に呼ばれるファイルの代わりに読み込ませる。


docker run --name mysql -v /Users/tartetatin/Desktop/LaravelServer/mysql:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=pass -d mysql:5.7



PHPとMySQLのコンテナを立ち上げて協調動作させる

先ほど作ったphp:customと、mysql:mysql を協調動作させる。

MySQLのコンテナはlinkで立ち上がるわけでは無いみたいだ。事前に立ち上げておかないといけないのか、、なんか方法がないのかな。


docker run -p 80:80 -v /Users/tartetatin/Desktop/LaravelServer:/var/www/html --link mysql:mysql --name php -d php:custom


で、立ち上がっているコンテナ一覧は、

docker ps -a

CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                NAMES

fd0ee19fa1f2        php:custom          "apache2-foreground"     2 minutes ago       Up 2 minutes        0.0.0.0:80->80/tcp   php

aa9bed662161        mysql:5.7           "docker-entrypoint.sh"   24 minutes ago      Up 24 minutes       3306/tcp             mysql

いい感じっぽい。

MySQLは動いてるんだろうか?

php:customで作ったコンテナに入って、/etc/hosts/を確認してみると、MySQLの情報があるっぽい。


docker exec -ti php bash

cat /etc/hosts

127.0.0.1 localhost

::1 localhost ip6-localhost ip6-loopback

fe00::0 ip6-localnet

ff00::0 ip6-mcastprefix

ff02::1 ip6-allnodes

ff02::2 ip6-allrouters

172.17.0.2 mysql 2df3c79ac7b2

172.17.0.3 <phpが動いてるコンテナのID>


ふむふむ。mysql含まれてるからいいっぽい。


composerインストール

phpの依存関係とかをアレするツールとして、composerをphpコンテナに入れる。

どうやんの。

この辺を参考に。

https://kore1server.com/175


curl -sS https://getcomposer.org/installer | php

mv composer.phar /usr/local/bin/composer

あとunzipとか入ってねえな、、、要る。

apt-get install zip

これY/nでるんで困ってるんだけどDockerfileとかで自動化するにはどうすればいいの。


Laravelでの最初のプロジェクト作り

composer global require "laravel/installer=~1.1"

composer create-project laravel/laravel MyFirstLaravel


行けたっぽさがある。


で、とりあえずMySQLとかの設定をしないといけないが、無視してアクセスしてみよう。

127.0.0.1では、Apacheの設定を放置したままなのでforbiddenが見えてる状態。


で。ここから、設定を変更していく。

・Apacheのデフォルトを、Laravelのデフォルトパスへと変更

・MySQLのIPの指定



設定はMyFirlstLaravelのフォルダにあるっぽい

.envファイルがそれ。


まず、ホストからLaravelのindexにアクセスできるようにしてみよう。


Apacheのデフォルトアクセスパスを、Laravelのデフォルトを指すように変更する。

apacheの該当設定のconfは以下にあるはず。

/etc/apache2/sites-available/000-default.conf


このファイルを一度hostへとコピーして、もう一度コンテナへとコピー。


docker cp <phpが動いてるコンテナのID>:/etc/apache2/sites-available/000-default.conf /Users/tartetatin/Desktop/LaravelServer/apache2/000-default.conf


で、コピッてきたconfの該当行を書き換える。


DocumentRoot /var/www/html/MyFirstLaravel/public



編集したファイルをコピーでHost -> Containerへと戻して、

docker cp /Users/tartetatin/Desktop/LaravelServer/apache2/000-default.conf <phpが動いてるコンテナのID>:/etc/apache2/sites-available/000-default.conf


phpの動いてるコンテナで、apacheの再起動

apachectl -k graceful


これで、apacheへとアクセスした時に、Laravelのパスへとアクセスできるようになった。

127.0.0.1にアクセスすると、確かにいい感じにインデックス表示された。まだMySQL動いてないんだけど。

スクリーンショット 2016-10-10 17.33.10.png

このコンフィグいじるとかその辺もなんかDockerfileに書き込めるといいんだろうなあ。と思うが面倒臭いのでいい。


MySQLの設定

次に、MySQLのパスを指定してみる。どうせなんか必要なんだろうし。、、必要なのか?

laravelの.envを書き換えればいいんだと思う。まあ面倒だから一度この辺で帰ろう。

wrote 2016/10/09 21:23:27

Unity iOS/Androidの実行時に関数のswapを行いたかった


概要

結果的には、C#の実行環境?としてのIL2CPPの挙動と、C#元来の動作の違いを噛み締めることになった。

知れたので満足している。


なお別の方法で関数のスワップはできる。めっちゃ泥臭い方法で。

自分のやり方が間違っている可能性が強いので、記録までに。



試したこと

1.iOS/Androidでのポインタのスワップによる実行時メソッドの入れ替え -> 失敗

2.IL生成と実行 -> 失敗


結果

methodInfoからポインタを引っ張ってunsafeな感じで複数のメソッドのポインタをswapすることはできる。

が、


現状のIL2CPPだと、

・変わるのはmethodInfoのポインタのみ

・変えられるmethodInfoは対象メソッドが"一切"実行される前のもののみ


という制約にぶち当たった。



また、IL生成と実行はDelegateを作って実行しようとするとUnsupportedで詰む感じだった。


どういう制約だったか順に書いていく。



サンプルプロジェクト

一連の動作を試したサンプルプロジェクトを下記にアップした。

MainSceneというシーンでPlayすると、動作が行われる。

エディタと実機で動作が異なる。

https://github.com/sassembla/Pointers



1.iOS/Androidでの実行上のメソッドの入れ替え -> 失敗

次のようなコードを書く

public class BaseClass {

public void BaseMethod() {

Debug.LogError("BaseMethod.");

}

}


public class NewClass {

public void NewMethod() {

Debug.Log("NewMethod!");

}

}


// method for swapping method pointers.

var baseMethod_MethodInfo = typeof(BaseClass).GetMethod("BaseMethod");

var newMethod_MethodInfo = typeof(NewClass).GetMethod("NewMethod");


var baseIntPtr = baseMethod_MethodInfo.MethodHandle.Value;

var newIntPtr = newMethod_MethodInfo.MethodHandle.Value;


unsafe {

// ready void* pointers.

var basePointer = baseIntPtr.ToPointer();

var newPointer = newIntPtr.ToPointer();

// swap method pointer, *base ---> *new.

*((Int64*)basePointer) = *((Int64*)newPointer);

}


var baseInstance = new BaseClass();

baseInstance.BaseMethod();// エディタではNewMethodが実行されるが、実機では元のBaseMethodが実行される。。。


baseMethod_MethodInfo.Invoke(baseInstance, new object[]{});// この呼び方だと実機でもエディタでもNewMethodが実行される。



IL2CPP上だと、変わるのはmethodInfoのポインタのみ

GetMethodとかから取得したmethodInfoと、インスタンスが保持しているメソッドのポインタが異なるため、

swapさせても書き換わるのはmethodInfoの関数だけだった。

太字の箇所での呼び出しで、実機とエディタでは動作に差が出る。


これがエディタとかの環境だと、methodInfoから得たポインタに対してswapを行った時点で、既存のインスタンスのメソッドとかのポインタも全て書き換わる。


最初試した時は、swapしたポインタの元であるmethodInfoからメソッド実行をした際、swapを観測した時点で「おっこれいけるやんけ」とか思ったんだけど、

インスタンスからの実行だと旧来のメソッドの内容が呼ばれてしまう。

ログで見るとこんな感じ。


エディタ上

NewMethod!

UnityEngine.Debug:Log(Object)

BaseClass:BaseMethod() (at Assets/Pointers.cs:16)

Pointers:PointerSwap() (at Assets/Pointers.cs:45)

Pointers:Start() (at Assets/Pointers.cs:24)


NewMethod!

UnityEngine.Debug:Log(Object)

BaseClass:BaseMethod() (at Assets/Pointers.cs:16)

System.Reflection.MethodBase:Invoke(Object, Object[])

Pointers:PointerSwap() (at Assets/Pointers.cs:47)

Pointers:Start() (at Assets/Pointers.cs:24)


実機上(iOS)

BaseMethod.

Pointers:PointerSwap()

Pointers:Start()

 

(Filename: /Users/builduser/buildslave/unity/build/artifacts/generated/common/runtime/UnityEngineDebugBindings.gen.cpp Line: 42)


NewMethod!

System.Reflection.MonoMethod:Invoke(Object, BindingFlags, Binder, Object[], CultureInfo)

Pointers:PointerSwap()

Pointers:Start()

 

(Filename: /Users/builduser/buildslave/unity/build/artifacts/generated/common/runtime/UnityEngineDebugBindings.gen.cpp Line: 42)


赤いところがまあ、、問題なわけで。実機ではメソッド呼び出し先がswapされていない。



IL2CPP上だと、コンパイル済みの時点で、インスタンス化されてから参照されるクラス情報と、インスタンス化時のクラス情報とに接続がないとか

そういうんじゃねーかな~と思っている。methodHandleから取得したポインタへの操作が反映されないっていう。


もしくはポインタの位置が全然異なるとかなのかな。だったらそれ追えれば良いんだけど。


ちなみにUnity5.5b1まで試したけど、実行状態は変わらなかった。



まあゲームエンジンからC++のポインタぶっ叩いてるだけだからな、、関係性はある程度動けばそれで良いでしょ的な。

ナチュラルボーンC#erな人とかには耐え難い差になりそう。

このへん、.Net Foundationに入った今後、どうなるんだろう.



インスタンス自体のメソッドのポインタをすげ替えるっていうことをすればいけると思うが。

現状の仕組みの上で頑張るのなんかダメな努力な気がするんでパス。


この状態が限界なのか、それとも自分がどこかでミスをしているのか、、、気になる。


変えられるmethodInfoは対象メソッドが"一切"実行される前のもののみ

日本語が難しい。

methodInfoをIL2CPP上で扱うときに面白かったのが、「methodのswapが可能なのはそのmethodを一度でも実行する前」みたいな制約があることだった。

例えばmethodInfoを得る前に対象のmethodをどこかのインスタンスで実行してしまうと、そのmethodのswapは不可能になる。

swapを実行しても結果が出ない。


なんかまああれですよ、実行時にテーブル作ったりしてるんじゃない?って思っていた。

Unityエディタ上でも発生するので、なんかおもしろ制約があるんだろう。

これについては、swap実行前に対象のmethodを実行しない、という前提が作れれば回避することができた。

逆に言えば、この制約を回避できたせいで、「うおーーいけるやろーー」って思ってしまったのが悲しかった。



2.IL生成と実行 -> 失敗


IL生成まではできるんだけど実行のためのDelegateが作り出せない

これはもうIL生成時にはっきりエラーが出る箇所があって、

DynamicMethodクラスのCreateDelegateメソッドで即死する。


var dMethod = new DynamicMethod("test", typeof(void), new Type[]{});


var il = dMethod.GetILGenerator();

il.EmitWriteLine("hello!!");

il.Emit(OpCodes.Ret);


var testDelegate = (Test.TestDelegate)dMethod.CreateDelegate(typeof(Test.TestDelegate));

testDelegate();


とかやると、CreateDelegateの時点でunsurpported吐いて同期的に死ぬ。


testDelegate error:System.NotSupportedException: /Users/builduser/buildslave/unity/build/Tools/il2cpp/il2cpp/libil2cpp/icalls/mscorlib/System.Reflection.Emit/DynamicMethod.cpp(21) : Unsupported internal call for IL2CPP:DynamicMethod::create_dynamic_method - System.Reflection.Emit is not supported.

  at System.Reflection.Emit.DynamicMethod.CreateDynMethod () [0x00000] in <filename unknown>:0 

  at System.Reflection.Emit.DynamicMethod.CreateDelegate (System.Type delegateType) [0x00000] in <filename unknown>:0 

  at Project2501.Shadowing.Maining () [0x00000] in <filename unknown>:0 

Project2501.Shadowing:Maining()

太字の部分が主な死因。


で、これがちょっと曲者で、

実は

var dMethod = new DynamicMethod("test", typeof(void), new Type[]{});


この行の時点ですでに死が確定してて、上記の実行まで行っていようがいなかろうが、

Unhandled Exception: System.NotSupportedException: /Users/builduser/buildslave/unity/build/Tools/il2cpp/il2cpp/libil2cpp/icalls/mscorlib/System.Reflection.Emit/DynamicMethod.cpp(26) : Unsupported internal call for IL2CPP:DynamicMethod::destroy_dynamic_method - System.Reflection.Emit is not supported.

  at System.Reflection.Emit.DynamicMethod.Finalize () [0x00000] in <filename unknown>:0 

UnityEngine.UnhandledExceptionHandler:PrintException(String, Exception)

UnityEngine.UnhandledExceptionHandler:HandleUnhandledException(Object, UnhandledExceptionEventArgs)


が人知れず出る。

new DynamicMethod実行の行をtry-catchで囲もうが出るので、なんだろ、、うん、、、みたいな感じ。


つまりまあ無理だ。


ちなみにこのエラーがでてもアプリケーション自体は元気に動き続ける。

なぜなのか。


とりあえずこの方法での実行時IL生成は無理でした。というまとめまでに。



結論

IL生成は無理っぽいので諦めようと思っているのだけれど、swapは頑張ってみたい。

間違いが知りたい。



追記 swapに関して試して効果がなかったこと

・API Compatibilityを2.0にする




wrote 2016/09/18 21:10:20

ワイヤレスヘッドフォンとかに関する自由とか制約とか機構について


概要

iPhone7からヘッドフォンジャック(ミニプラグ)がなくなるので、ワイヤレスヘッドフォン使う人増えそうで。

ここ4年くらいずーっとワイヤレスヘッドフォン使ってた上で知ったいろんな機構とかをまとめて説明しようと思う。


ワイヤレスヘッドフォンとスマフォOSとミュージックアプリ、複数の組み合わせがありえて、

その動作には様々な制約や自由、操作方法、通知機構、動作機構がある。


それらを適当にまとめようっていう腹。


要素

適当に次のような要素がある。

ワイヤレスヘッドフォンまわりの機構とかについて、この機構はこの組み合わせだとついてたよ~、みたいな

具体的な記録を、自分が体験したものだけに関してまとめていく。


OS iOS/Androidとか

端末 iPhoneとかNexusとか

ワイヤレスヘッドフォン種類 ワイヤレスなんだけど線あり/なし とか

メーカー BOSEとかEARINとかBeatsとか



っていいつつ、まずは有線のヘッドフォンまわりについて書かせてもらう。音質とかについては触れない。やっててくれ。


ワイヤレスじゃない場合の機能・機構

次のような機構が入っている組み合わせがあるので使うといいと思う。


1.プラグを抜いたら音が止まる

2.出力機器「ごと」の音量設定

3.再生中に新規に出力機器を追加したら、その機器で続きから鳴る


ワイヤレスなオーディオ機構は、ワイヤレスじゃないオーディオ機構の延長線上にある感じで、

ワイヤレスでない環境で動かない機構はワイヤレスな機構でももちろん動かない。


つまりワイヤレスでない時点でゴミな場合ワイヤレスになってもその環境は改善されない可能性があるってことだね!!

というかほぼ確実に改善されないので「俺はろくでもない方を使っていたんだなあ」とでも思ってくれ。



そんなミニプラグと再生機器にまつわる機能・機構、順に細かく書いていこう。



1.プラグを抜いたら音が止まる

そのまんまプラグを抜いたら音が止まるかどうか。

iOSとか一部のAndroid端末(これOS関係ないんじゃないかな、作ったメーカーとか時期がカスかどうかの二択)は、

音楽再生中にプラグを抜くと音が止まる。

この動作は使っているアプリによっても影響を受ける感じなのだけれど、

・音楽系:止まる

・動画系:スピーカーを変えて流れ続ける

という動作の差はある感じ。



2.出力機器「ごと」の音量設定

iPhoneとかMacBookとかだと、音声出力の機器単位で細かく再生音量を記録してくれている。

なので、有線でプラグ刺した時に、その機器を判別して音量がセットされる。


Androidはどうだったっけな、、、


本体スピーカーの音量設定とは別に音量がセットされるので、

・本体音量はゼロ

・特定のスピーカー(ヘッドフォン)をつないだ時の音量をいじる

というふうにしておくと、AV見てる時に嫁さんがプラグを抜いてワァーオ みたいな状況にならないで済む。



3.再生中に新規に出力機器を追加したら、その機器で続きから鳴る

家でiPhoneとかから据え置きのBTスピーカーとかに接続して音楽流してて、

さて出かけるか、ってなった時に、プラグにヘッドフォンさすとそこから今聞いてる音がそのまま出る。


シームレスなお出かけ体験ができるかどうか、、っていう向きもあるけど、

プラグをさせば不用意に流れ出したアニソンとかを物理的な手段でもって一瞬で封印できるという大事な一面もある。



この1~3を満たしてる組み合わせだと、下記のワイヤレスヘッドフォンをつないでいる場合の挙動が上乗せされる感じになる。


というかここまでの条件すら満たしてない環境があったら、

それはもうワイヤレスヘッドフォンでも劣悪な環境と言っても過言ではない(過言)



ワイヤレスな場合でさらに追加される機能・機構

4.接続、切断したらビープ音が鳴る

5.OSの画面に電池残量や接続具合が出る

6.専用アプリで電池残量や接続状態がわかる

この辺は本当に選んだワイヤレスヘッドフォンごとに挙動が異なる。

ミニプラグという物理的なインターフェースの殻を失ってしまってめっちゃフリーダム。


4.接続、切断したらビープ音が鳴る

鳴るやつと鳴らないやつがある。


BOSEはこの辺大変優秀だった

繋がっても鳴るし、切断しても鳴るし、音量変えるだけでも小さなビープ音出たし。


ほか

だいたい音がでない。

体験としてはまあいいんだけど、完全無線(左右の端末が線でつながってない)EARINとかが凄まじくて、

片側だけ切断したときのリカバーがめっちゃくちゃ甘い。片側だけ停止したりする。しかもそのまま流れる。


お前切断くらい検知して音流したまま自動復旧しろやっていう感じになる。

ちなみに一時停止とかかけると復旧するケースと、一度ケースにしまわないと復旧しないケースがある。

90%くらいは一時停止で復旧する。



5.OSの画面に電池残量や接続具合が出る

ヘッドフォンの左右の端末が有線で繋がっている機器の場合、ほぼ確実にOS上に「ヘッドフォンのバッテリー表記」が追加表示される。

これは接続/切断の目安にもなるので、すごくいいと思う。


このへんはBTがバッテリーに関する項目を持ってたから共通認識的な感じで表示が出せてるんだと思う。

下記画像みたいなのが画面のどこか、時計の横とかに出る。

icon.png



が、EARINに代表されるような左右独立型の端末が生まれてから、状況が変わった。


左右独立型の場合、これが、、まあ、、EARINなんだけど、電池表示がOS画面に一切出ない。

なんと通知欄にも出ない。

aaa.png



6.専用アプリで電池残量や接続状態がわかる

5を解消するための機構というか。

専用Appで接続状態、バッテリー状態とか低音強調とか左右のバランスとか弄れる。

IMG_1877.PNG


というか専用アプリ以外から状況がわからないと言った方がいい。

この辺はヘッドフォンごとのカスタマイズ に繋がるんで、いいところもあるんじゃねーーかなーーと思いつつ、

デフォルトで使える有用な道具が大好きなのでカスタマイズ厨乙みたいなカスタムしないと使い物にならない物体は避けたいところ。



操作方法について

ワイヤー(左右端末間での有線での接続)があるならそのへんにボタンが来たりする。

ので、物理的な操作が割と楽にできるので良い。


左◯-----この辺にあるやつ ------------------◯右



で、左右独立型はどうなの?っていうと、インターフェースが無い or あるんだけど押せるか??これ??? っていう。

AppleWatchとか使ってるとiPhone上のミュージックアプリの音量とか曲送りとか自由にできるので自分はこれでいいやっていう気分だけど、どうするのが一般化するんだろうね。



サウンドアプリ連携専用のBT時計装置とか? ありそう。


wrote 2016/09/09 11:48:51

nodeでmaterial ui使う


概要

パパッとセッティングしたい。と思ってたんだけど、、、結局WebPackに依存しないとダメなのか。


実行はnodeでやりたいんで、混ぜられないものかと考えてた。

最終的にできた。

このへんを参考にした。


webpack+React+material-uiの環境を最小手順で作成

http://qiita.com/takaki@github/items/724d97a20d3ae194ded4



webpack is 何

依存関係を記述するとそれを解決できるようにゴインゴイン動くツール。

importって書けるの楽だよね、、っていう。



プロジェクト作成

適当にフォルダを作って、

npm init

npm install -g webpack

npm install --save react react-dom babel-preset-react babel-loader babel-core

npm install --save babel-preset-es2015

npm install --save material-ui



要素を作成。


touch index.html

mkdir src

touch src/index.js

touch webpack.config.js

touch .babelrc

それぞれのファイルの内容を書いていく。


index.html

<!DOCTYPE html>

<html>


<head>

  <title>Webpack Excercise</title>

  <meta charset="UTF-8">

  <meta name="viewport" content="width=device-width, initial-scale=1.0">


</head>


<body>

  <div id="content"> Content </div>

  <script src="static/bundle.js" charset="utf-8"></script>

</body>


</html>


bundle.jsってのがまあ、WebPackで作り出される結果ファイルなのね。出力されるファイルの名前や場所の指定はwebpack.config.jsでやってる。

webpack.config.js

module.exports = {

  entry: {

    jsx: "./src/index.js"

  },

  output: {

    path: __dirname + "/static",

    filename: "bundle.js"

  },

  module: {

    loaders: [

      { test: /\.js$/,  loader: "babel-loader", exclude: /node_modules/ }

    ]

  }

}

outputのとこで、いろいろやったファイルをstatic/bundle.jsに出力するようになってるぽい。


で、この中で、さらにコンパイラとしてbabelが指定されてる。

babelの設定ファイルは下記。


.babelrc

{ "presets": ["react", "es2015"] }


こんな感じでいいっぽい。

そーかー jsxのコンパイラがbabelに入ったってこういうことなのか。


コンパイル対象となる.jsは、


index.js

var React = require('react');

var ReactDOM = require('react-dom');


import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';

import RaisedButton from 'material-ui/RaisedButton';


ReactDOM.render(

<div>

<MuiThemeProvider>

<RaisedButton label="Default" />

</MuiThemeProvider>

</div>,

document.getElementById('content')

);


濃い字のところのimportが使いたいがために、ここまでの苦労を、、、うーーん、、時代があるなあ、、もっと楽になってくれ。

で、ここまでいくと、


webpack --progress --color

でindex.jsがゴインゴインとコンパイルできる。


結果的にブラウザでindex.htmlを開くと、


スクリーンショット 2016-09-07 19.27.47.png


やったぜ。



保存するたびにWebpacで自動的に

今回はやらないことにした。

nodeでサーブしてるサービスと連携したいので、ウザい。


index.jsからnodeにアクセスするのが書けるので、データのプッシュとかローディングについてはそれで解決する。



wrote 2016/09/07 18:16:55

MaterialUI使ってみる


概要

このページを参考に動かしてみる。

http://blog.takanabe.tokyo/2015/12/11/1778/


最終的には、左右のペーン、右ペーン内にリストで項目表示、みたいな画面が作りたい。



プロジェクトつくる

まずはnpm管理下のプロジェクトを作成。

mkdir mat

cd mat 

npm init


package.jsonに次を記載

{

  "name": "mat",

  "version": "1.0.0",

  "description": "",

  "main": "index.js",

  "scripts": {

    "test": "echo \"Error: no test specified\" && exit 1",

    "start": "webpack-dev-server --hot --inline --progress --colors",

    "build": "webpack --progress --colors"

  },

  "devDependencies": {

    "babel-core": "^5.8.25",

    "babel-eslint": "^4.1.3",

    "babel-loader": "^5.3.2",

    "babel-runtime": "^5.8.25",

    "css-loader": "^0.19.0",

    "eslint": "^1.6.0",

    "eslint-loader": "^1.1.0",

    "eslint-plugin-react": "^3.5.1",

    "fbjs": "^0.2.1",

    "file-loader": "^0.8.4",

    "style-loader": "^0.12.4",

    "webpack": "^1.12.2",

    "webpack-dev-server": "^1.12.0",

    "webpack-hot-middleware": "^2.2.0"

  },

    "dependencies": {

    "classnames": "^2.1.2",

    "fbjs": "^0.3.2",

    "material-ui": "^0.13.0",

    "react": "^0.14.0",

    "react-addons-create-fragment": "^0.14.0",

    "react-addons-pure-render-mixin": "^0.14.0",

    "react-addons-transition-group": "^0.14.0",

    "react-addons-update": "^0.14.0",

    "react-dom": "^0.14.0",

    "react-hot-loader": "^1.3.0",

    "react-redux": "^3.1.0",

    "react-tap-event-plugin": "^0.2.0",

    "redux": "^3.0.2"

  },

  "author": "",

  "license": "ISC"

}


で、

npm install


次に、webpack.config.jsを作成して、、いろいろ書きこむ。

module.exports = {

  context: __dirname,

  entry: {

    jsx: "./src/index.jsx",

    css: "./src/main.css",

    html: "./src/index.html",

  },


  output: {

    path: __dirname + "/static",

    filename: "bundle.js",

  },

  module: {

    preLoaders: [

        //Eslint loader

      { test: /\.jsx?$/, exclude: /node_modules/, loader: "eslint-loader"},

    ],

    loaders: [

      { test: /\.html$/, loader: "file?name=[name].[ext]" },

      { test: /\.css$/, loader: "file?name=[name].[ext]" },

      { test: /\.jsx?$/, exclude: /node_modules/, loaders: ["react-hot","babel-loader"]},

    ],

  },

  resolve: {

    extensions: ['', '.js', '.jsx']

  },

  eslint: {

    configFile: './.eslintrc'

  },

};

eslintって何、ってなってるけどとりあえずやってみる。

touch .eslintrc


{

  "env": {

    "es6": true,

    "browser": true,

    "node": true

  },

  "rules": {

    "curly": 0,

    "comma-dangle": [2, "never"],

    "comma-spacing": 0,

    "eqeqeq": [2, "allow-null"],

    "key-spacing": 0,

    "no-underscore-dangle": 0,

    "no-unused-expressions": 0,

    "no-shadow": 0,

    "no-shadow-restricted-names": 0,

    "no-extend-native": 0,

    "no-var": 2,

    "new-cap": 0,

    "quotes": 0,

    "semi-spacing": 0,

    "space-unary-ops": 0,

    "space-infix-ops": 0,

    "consistent-return": 0,

    "strict": 0

  },

  "parser": "babel-eslint",

  "plugins": [

    "react"

  ],

  "ecmaFeatures": {

    "arrowFunctions": true,

    "jsx": true

  }

}


ああ、babel、、なるほど、、コンパイラの起動とかの設定なのか。概念としてはlint、っていう。


srcフォルダを作って、中にindex.htmlとか置く

mkdir src

touch ./src/index.html

touch ./src/index.jsx

touch ./src/main.css


で、npm run buildで、package.jsonで指定したbuildコマンドを実行。

npm run build


おお、、なんかコンパイルできたぞ、、


で、次に、index.jsxにいろいろ書いたりするんだけど、だいたいかいてあるまま進められる。


ただそのままだと動かなかったので、App.jsxだけ手を加えた。

import React, { Component, PropTypes } from "react";

import { bindActionCreators } from 'redux';

import { connect } from 'react-redux';

import Header from '../components/Header';

import MainSection from '../components/MainSection';


class App extends Component {

  render() {

    return (

      <div>

        <Header />

        <MainSection />

      </div>

    );

  }

}


export default App;


Material UIの作成は、componentsフォルダを作っていろいろファイル置いて、そこにReactComponentを記述しがてら行う。

mkdir components

touch ./components/Header.jsx

touch ./components/MainSection.jsx


Header.jsx

import React, { PropTypes, Component } from 'react';


import mui, {AppBar} from 'material-ui';

const ThemeManager = require('material-ui/lib/styles/theme-manager');

import MyRawTheme from '../src/material_ui_raw_theme_file'


class Header extends Component {

  static get childContextTypes() {

    return { muiTheme: React.PropTypes.object };

  }


  getChildContext(){

    return {  muiTheme: ThemeManager.getMuiTheme(MyRawTheme)};

  }


  render() {

    return (

      <header className="header">

        <h1>AppBar Component</h1>

        <AppBar title="React + Redux + Material UI Boilerplate" />

      </header>

    );

  }

}


export default Header;


これでAppBarが出る。ほうほう。

細かい設定値はちょっと濃い行で、ファイルを使って指定している。

(面倒なのでオフってみた。)


次に、MainSection.jsx

import React, { Component, PropTypes } from 'react';

import mui, {CircularProgress,

             Tabs,

             Tab,

             DatePicker

            } from 'material-ui';


class MainSection extends Component {

  render() {

    return (

      <div>

        <h1>Progress Component</h1>

        <CircularProgress mode="indeterminate" size={1.5} />

        <CircularProgress mode="indeterminate" color={"red"} size={2} />

        <br/>


        <h1>Tab Component</h1>

        <Tabs>

          <Tab label="Tab One" value="0" />

          <Tab label="Tab Two" value="1" />

          <Tab label="Tab Three" value="2" />

        </Tabs>

        <br/>


        <h1>DatePicker Component</h1>

        <DatePicker hintText="Portrait Dialog" />

        <br/>

      </div>

    );

  }

}


export default MainSection;


で、ここまで書いたあと、npm start すると、ウォッチ状態になる + サーバ起動して、ブラウザで観れるようになる。

npm start

スクリーンショット 2016-09-07 15.02.45.png


とりあえず2016/09/07現在でも動いてくれてよかった。


reduxって一体なにで、何してるんだろう、っていうのを後で追う。



MaterialUIでテーブルを表示してみる

http://www.material-ui.com/#/components/table から、

コードを見る(<>マークを押す) -> components フォルダにTableExampleSimple.jsxっていう名前でファイルを作る。


import React from 'react';

import {Table, TableBody, TableHeader, TableHeaderColumn, TableRow, TableRowColumn} from 'material-ui';// 末尾を'material-ui'に変更してパスを合わせてる


const TableExampleSimple = () => (

  <Table>

    <TableHeader>

      <TableRow>

        <TableHeaderColumn>ID</TableHeaderColumn>

        <TableHeaderColumn>Name</TableHeaderColumn>

        <TableHeaderColumn>Status</TableHeaderColumn>

      </TableRow>

    </TableHeader>

    <TableBody>

      <TableRow>

        <TableRowColumn>1</TableRowColumn>

        <TableRowColumn>John Smith</TableRowColumn>

        <TableRowColumn>Employed</TableRowColumn>

      </TableRow>

      <TableRow>

        <TableRowColumn>2</TableRowColumn>

        <TableRowColumn>Randal White</TableRowColumn>

        <TableRowColumn>Unemployed</TableRowColumn>

      </TableRow>

      <TableRow>

        <TableRowColumn>3</TableRowColumn>

        <TableRowColumn>Stephanie Sanders</TableRowColumn>

        <TableRowColumn>Employed</TableRowColumn>

      </TableRow>

      <TableRow>

        <TableRowColumn>4</TableRowColumn>

        <TableRowColumn>Steve Brown</TableRowColumn>

        <TableRowColumn>Employed</TableRowColumn>

      </TableRow>

    </TableBody>

  </Table>

);


export default TableExampleSimple;

で、export句てのがあるのに初めて気づいた。ほう。


containersフォルダのApp.jsx側を以下のように変更

import React, { Component, PropTypes } from "react";

import { bindActionCreators } from 'redux';

import { connect } from 'react-redux';

import Header from '../components/Header';

import MainSection from '../components/MainSection';

import TableExampleSimple from '../components/TableExampleSimple'


class App extends Component {

        // <Header />

        // <MainSection />

  render() {

    return (

      <div>

      <TableExampleSimple />

      </div>

    );

  }

}


export default App;


import句で、コンポーネントの要素 from ファイルパス みたいに指定できるんだな。なるほど。

で、App コンポーネントはUIの根っことして、index.jsxから参照されている。

import React from "react";

import ReactDOM from "react-dom";

import injectTapEventPlugin from "react-tap-event-plugin";


import App from '../containers/App';


//Needed for React Developer Tools

window.React = React;


//Needed for onTouchTap

//Can go away when react 1.0 release

//Check this repo:

//https://github.com/zilverline/react-tap-event-plugin

injectTapEventPlugin();


ReactDOM.render(

  <App />,

  document.getElementById("root")

);


色つきの部分での接続はこういう理屈になってたんだなーー把握。

表示はこんな風になった。


スクリーンショット 2016-09-07 17.16.00.png


で、これあの、、手でJSXに書き直さないといけないの?

TableExampleSimple.jsx

import React from 'react';

import {Table, TableBody, TableHeader, TableHeaderColumn, TableRow, TableRowColumn} from 'material-ui';



const TableExampleSimple = () => (

  <Table>

    <TableHeader>

      <TableRow>

        <TableHeaderColumn>ID</TableHeaderColumn>

        <TableHeaderColumn>Name</TableHeaderColumn>

        <TableHeaderColumn>Status</TableHeaderColumn>

      </TableRow>

    </TableHeader>

    <TableBody>

      <TableRow>

        <TableRowColumn>1</TableRowColumn>

        <TableRowColumn>John Smith</TableRowColumn>

        <TableRowColumn>Employed</TableRowColumn>

      </TableRow>

      <TableRow>

        <TableRowColumn>2</TableRowColumn>

        <TableRowColumn>Randal White</TableRowColumn>

        <TableRowColumn>Unemployed</TableRowColumn>

      </TableRow>

      <TableRow>

        <TableRowColumn>3</TableRowColumn>

        <TableRowColumn>Stephanie Sanders</TableRowColumn>

        <TableRowColumn>Employed</TableRowColumn>

      </TableRow>

      <TableRow>

        <TableRowColumn>4</TableRowColumn>

        <TableRowColumn>Steve Brown</TableRowColumn>

        <TableRowColumn>Employed</TableRowColumn>

      </TableRow>

    </TableBody>

  </Table>

);


export default TableExampleSimple;



UIの表示してるプロジェクトと、nodeのプロジェクトをどうマージするか

ぶっちゃけ通信周りとかはnodeのほうが取り回しが楽なんだけど、package.jsonにあるような要素の中から、webpackとreduxを省いても

無事にjsxからコードが生成できると思うのだがどうか、、まあ今回は無理かな。



exportの別の書き方

こんな風に書くこともできた。

import React, { Component, PropTypes } from "react";

import {TextField} from 'material-ui';


export default class TextFieldExampleSimple extends Component {

  render() {

    return (

      <div>

        <TextField

          hintText="+-> lua codes for devices here."

          multiLine={true}

          rows={3}

          rowsMax={10}

          fullWidth={true}

        />

      </div>

    );

  }

}


用途に応じてって感じかな。



reduxって何で何してんの

react-reduxとreduxがそれぞれ依存(package.json)にあって、

つづく。


wrote 2016/09/07 18:06:00

今更Reactことはじめ


概要

React + MaterialUIで適当にウェッサイ作る。

SSRで動いてるのはすでに自社とかでもあったんだけど、全部自分で最初から描いてみよ、ってなるのは初。


UnityのWebGLで作ってもいいんだけど、せっかくだからやってみようと思う。

次こういう機会があったら、試しにAngular2を使ってみよう(微レ存


ちなみにパパっと使う上ではReact大満足。



StarterKit

Facebookが作ってるスターターキットがあったので使う。

https://facebook.github.io/react/docs/getting-started.html


こいつにはオフラインでもreactのフローが動くように幾つかのjsファイルが含まれている。


build/

react-dom-server.js

react-dom-server.min.js

react-dom.js

react-dom.min.js

react-with-addons.js

react-with-addons.min.js

react.js

react.min.js


これらだけで動かせる。

jsxのコンパイルだけは、下記watchを働かせるために、どこかから仕入れてきていた。

jsx --watch src/ build/

どっからもってきた(npm install ? )したのかよくわかってない。


GUI要素をJavaScriptで書く

書けるのな~~楽な~~~~~。

ReactDOMってのがグローバルに存在してるんで、htmlに書いてある適当な要素に対して、

<!DOCTYPE html>

<html>

  <head>

    <meta charset="UTF-8" />

    <title>Hello React!</title>

    <script src="build/react.js"></script>

    <script src="build/react-dom.js"></script>

    <script src="https://npmcdn.com/babel-core@5.8.38/browser.min.js"></script>

    <script type="text/babel" src="src/helloworld.js"></script>

  </head>

  <body>

    <div id="example"></div>

  </body>

</html>



下記でGUI要素をJavaScriptからアタッチできる。

ReactDOM.render(

<CommentBox />,

document.getElementById('example')

);



で、アタッチする要素CommentBoxについては、これもjsから書ける。

var CommentBox = React.createClass({

render: function() {

return (

<div className="commentBox">

<h1>Comments</h1>

<CommentList />

<CommentForm />

</div>

);

}

});

render関数が描画される。

これらcreateClass関数で生成した要素は、コンポーネントという単位の雛形になる。

コンポーネント名としては、変数名があてがわれる。(上の場合だとCommentBoxっていうコンポーネントになる。


JSXで書いたrender関数の要素には、他のコンポーネントを入れ子にすることができる。

このコンポーネント間の参照の解釈タイミングは実際の実行時のため、コンポーネントを書いてる位置は問題にならない。

ただし、ReactDOM.render内で参照されるコンポーネントについては、必ず全ての参照がReactDOM.renderが呼ばれる前に解決されている必要がある。

つまりReactDOM.render関数は最後に書こうなという感じ。



入れ子になってる要素 CommentListとかCommentFormは、

同じようにcreateClass関数で作成できる。

var CommentForm = React.createClass({

render: function() {

return (

<div className="commentForm">

Hello, world! I am a CommentForm.

</div>

);

}

});


var CommentList = React.createClass({

render: function() {

return (

<div className="commentList">

<Comment author="Pete Hunt">This is one comment</Comment>

<Comment author="Jordan Walke">This is *another* comment</Comment>

</div>

);

}

});


なんて楽なんだ、、、、



エラーの出方

例えば var Commentって書かれるべきクラスをCommmentとかtypoした場合、

CommentListから参照できない要素があるよっていうエラーが出る。



データを適応する

上記でベタが記してあるCommentListの中身を、jsonから読むようにする。

まずデータを用意して、

var data = [

{id: 1, author: "Pete Hunt", text: "This is one comment from json."},

{id: 2, author: "Jordan Walke", text: "This is *another* comment  from json"}

];


次にデータを使うところまでの経路にデータ読み込む旨を書いていく。

ReactDOM.render(

<CommentBox data={data} />,

document.getElementById('example')

);


CommentBoxにデータを入れてるんで、CommentBoxにもデータをCommentListへと伝播するためのコードを書く。

var CommentBox = React.createClass({

render: function() {

return (

<div className="commentBox">

<h1>Comments</h1>

<CommentList data={this.props.data} />

<CommentForm />

</div>

);

}

});



CommentListにデータを渡したいので、data = {this.props.data} とか書く。

下流のパラメータ名 = {this.props.上流からのデータの名前} という記法で、データのマッピングがされるみたいだ。

ここでのthisはこれ、CommentBoxのインスタンスなのかな。


で、それを受けるCommentListは、

var CommentList = React.createClass({

render: function() {

var commentNodes = this.props.data.map(function(comment) {

return (

<Comment author={comment.author} key={comment.id}>

{comment.text}

</Comment>

);

});

return (

<div className="commentList">

{commentNodes}

</div>

);

}

});


この要素に渡ってくる、props内のdataという名前のパラメータに対して、JSXでDOM要素を返す関数を、組み込みのmap関数で適応する。

ようはCommentのリストを作り出している。らくちんかよ。


濃い要素の部分はJSXでCommentクラスの描画可能なパラメータを返してきてて、これがそのまま、

はるばるReactDOM.renderから渡ってきたjsonデータの中身の展開部分になっている。


Commentコンポーネントに対し、author、key、textをそれぞれ取り出して使用している。

author=author、key=id、で、このkey部分が特にコンポーネントで固定された意味を持っている。


っていうかkeyは自前定義ではなく、propsには初めから、virtualDOM用の要素としてkeyというパラメータが用意されている。

mapとかでリストを作り出す際に、uniqueを発揮するためにセットする必要がある。

差分更新のために、リストの要素にもunique性が必要な訳だ。


keyはそのuniqueをReact側が把握するために使用する。


で、最終的に{commentNodes}をreturnして終わり。

無事にビューへとデータが反映される。

すげーなーーこれ。



パラメータをサーバから持ってくる = APIを呼んでその値を入れるには?

いろんなパラメータ、状態、遷移を、なんかしっかりしたハンドラの仕組みによってものすごく折りたためる。


・取得元のurlを外部から与える形にできることによって、データ取得のソースの記述を外部化できる

・初期値をセットできる

・コンポーネントごとの挙動をそのurlパラメータに依存し、実行時処理の関数化ができる


var CommentBox = React.createClass({

loadCommentsFromServer: function() {

$.ajax({

url: this.props.url,

dataType: 'json',

cache: false,

success: function(data) {

this.setState({data: data});

}.bind(this),

error: function(xhr, status, err) {

console.error(this.props.url, status, err.toString());

}.bind(this)

});

},


getInitialState: function() {

return {data: []};

},


componentDidMount: function() {

this.loadCommentsFromServer();

setInterval(this.loadCommentsFromServer, this.props.pollInterval);

},


render: function() {

return (

<div className="commentBox">

<h1>Comments</h1>

<CommentList data={this.state.data} />

<CommentForm />

</div>

);

}

});

上から順に、

loadCommentsFromServerっていう自前の関数定義をして、jQuery使ってデータを取得、成功したらdataに対してdataを反映。

getInitialStateっていう組み込みの関数定義をして、デフォルトのdata値をセット、


componentDidMountっていう組み込みの関数定義をして、このコンポーネントがマウントされた際、

loadCommentsFromServerを呼び出してdataに入力するjsonを取得、アタッチする。


render関数の中身にも変更があり、初期値としてセットした空のデータをまず読ませるために、this.state.dataを使っている。

ちなみにここでjqueryに依存してるけどサンプルがそうなってるだけなんでReact自体にjQuery依存はない。

(で、jQuery経由のsetStateでwarningが出るんですがこれは一体どうすればいいのか。)


新しいコメントの入力を行う機構を作りこむ

入力が行われたら、新しいCommentをサーバに送り込むことになる。

イベントの着火自体はCommentFormで行われるので、その入力を上位CommentBoxとかに届けたい。


変更 = コメントの追加があった際、親であるCommentBoxから、子であるCommentListに要素を加えることになるため、

親コンポーネントに何らかの方法でデータを伝達、処理させる必要がある。


ComentBoxでonCommentSubmitというプロパティを自作して、

下位のCommentFormに渡してCommentFormから入力時にCommentBoxの関数を実行できるようにする。

小さな範囲での密結合を生んでこれを解決している。

var CommentForm = React.createClass({

getInitialState: function() {

return {author: '', text: ''};

},

handleAuthorChange: function(e) {

this.setState({author: e.target.value});

},


handleTextChange: function(e) {

this.setState({text: e.target.value});

},


handleSubmit: function(e) {

e.preventDefault();


// 入力をvalidate

var author = this.state.author.trim();

var text = this.state.text.trim();

if (!text || !author) {

return;

}

this.props.onCommentSubmit(JSON.stringify({author: author, text: text}));

this.setState({author: '', text: ''});

},


render: function() {

return (

<form className="commentForm" onSubmit={this.handleSubmit}>

<input

type="text"

placeholder="Your name"

value={this.state.author}

onChange={this.handleAuthorChange}

/>

<input

type="text"

placeholder="Say something..."

value={this.state.text}

onChange={this.handleTextChange}

/>

<input type="submit" value="Post" />

</form>

);

}

});


nameとtextというテキストインプット2つをformで囲い、onSubmitにhandleSubmit関数をセットする。

明示的にthisが使えるのが嬉しい。


最終的にonSubmit関数内で、propsで渡ってくる関数onCommentSubmitを実行している。

onCommentSubmit関数は、CommentFormの親であるCommentBoxから渡している。


var CommentBox = React.createClass({

loadCommentsFromServer: function() {

$.ajax({

url: this.props.url,

dataType: 'json',

type: 'GET',

cache: false,

success: function(data) {

this.setState({data: data});// これがいけないぽい。

}.bind(this),

error: function(xhr, status, err) {

console.error(this.props.url, status, err.toString());

}.bind(this)

});

},

handleCommentSubmit: function(comment) {

$.ajax({

url: this.props.url,

dataType: 'json',

type: 'POST',

data: comment,

success: function(data) {

this.setState({data: data});

}.bind(this),

error: function(xhr, status, err) {

console.error(this.props.url, status, err.toString());

}.bind(this)

});

},

getInitialState: function() {

return {data: []};

},

componentDidMount: function() {

this.loadCommentsFromServer();

setInterval(this.loadCommentsFromServer, this.props.pollInterval);

},

render: function() {

return (

<div className="commentBox">

<h1>Comments</h1>

<CommentList data={this.state.data} />

<CommentForm onCommentSubmit={this.handleCommentSubmit} />

</div>

);

}

});


onCommentSubmitというラベルで、CommentBoxのhandleCommentSubmit関数が接続されている。

最終的に渡ってきたcommentデータがpostされ、結果がsetStateを呼び出し、

変更が加えられたdataはそのままCommentListへと伝達される。


便利=~~



nodeとかサーバで動かすには

React routerとかが便利そう。

http://qiita.com/koba04/items/737c783f1189355e053f


ServerSideRendering

サーバ側でReact動かして完成したHTML(実際には動的な可変要素を含む)を返す技術。

htmlだけを返してローディングさせるのと対比されている。



wrote 2016/09/06 16:15:38

Mackerelのハンズオン


概要

Mackerelハンズオン

http://mackerelio.connpass.com/event/38331/


当選したので行ってきた。

本来は別の日だったんだけど、台風でズレて9/5になった。


はてな、東京のはわりとぬる舗から近いということがわかった。



資料

ひこうかい。



Mackerel概要

push型。監視対象サービスにインストールされたエージェントがデータをpushする。

zabbixとかnagiosはpull型。


デザイナー専属でいるので一貫性があって素敵。


GUI、CLI、CLIからAPI経由で制御、とかいろんなインターフェースがある。


やってみる系

AWSに仮の監視対象を用意してくれてた。



Makerelにおけるグルーピングとか用語

オーガニゼーション x N

サービス x M

ロール x L


みたいな並び。



エージェントを監視対象サーバにインストール

下記コマンドを実行後、インストールコマンドがサジェストされるんで、それを入れる。


curl -fsSL https://mackerel.io/assets/files/scripts/setup-yum.sh | sh


APIKeysをエージェントに登録

MakerelのユーザーページからAPIKeysが取得できるんで、それを監視対象のエージェントに入れる。


sudo mackerel-agent init -apikey="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"



エージェントの起動


sudo /etc/init.d/mackerel-agent start



サービスとロールの設定

サービス、そこに所属するロールを作成



作成したサービス/ロールと、ホスト(エージェントをインストールしたとこ)との連携

Hosts から、すでにMackerelのエージェントを入れたマシンが表示されてるので、

そこに先ほど作成したサービス/ロールを割り当てることができる。



モニタリングからアラート設定の流れ

Monitors > New Monitor とかで作成。

GUIから設定できる。便利だ。



アラートが出たらどうなるの?

時系列で可視化される。

と同時に、「チケット」が作成される。

スクリーンショット 2016-09-05 16.12.49.png


スクリーンショット 2016-09-05 16.14.57.png


かなり素敵。

メールも届く。


スクリーンショット 2016-09-05 16.21.04.png



原因を排除すれば、アラートは消えて、チケットも消化される。

あと解消しましたメールも届く。


スクリーンショット 2016-09-05 16.21.28.png



特定のミドルウェアに関してのプラグインをエージェントに入れる

MySQLとかApacheとかの監視ができるプラグインを入れてみる。


プラグインはここで公開されてる。

https://github.com/mackerelio/mackerel-agent-plugins



プラグイン集はこれスクリプトで、下記コマンドでエージェントが入ってるPeerにインストールできる。

sudo yum install -y mackerel-agent-plugins

あとは名指しで、起動するプラグインを指定してエージェント再起動。

/etc/mackerel-agent/mackerel-agent.conf を編集

sudo /etc/init.d/mackerel-agent restart


プラグインはstdoutを適当なフォーマットで吐ければいい

プラグインは単体でも実行できて、stdoutにstringを吐くことができればOKなのか。

フォーマットはタブで区切られてて改行があればいいぽい。


なるほどな~~~



サービスメトリックについて

ホストをまとめたもの = サービスに対してのメトリック。

ようはユーザーが自由に定義していいメトリック。



公式ヘルプ

https://mackerel.io/ja/docs/


fluentdでMackerelに送り込む方法とかが書いてあって面白い。

https://mackerel.io/ja/docs/entry/advanced/fluentd



Q&A

Q.Mackerel自体の死活監視ってどうなるの?

A.mackerel.status.io あるよ

http://mackerel.status.io


Q.Mackerelのエージェントって何製?

A.go。フットプリント小さいんで良い。


感想

Mackerel、ビジュアライズがとても綺麗で見やすかった。

適当になんか作るときに使おうと思う。


ハンズオンは監視対象のインスタンスまで用意してくださっていて、とても快適に学ぶことができた。

お茶もあったし。


企画してくださった方、当日お世話になったTAやTの方、ありがとうございます。






wrote 2016/09/05 15:06:37

nodeを使って2501サーバの簡易模倣


概要

ビューを持ち出すわけにいかなかったので、でっち上げる。

写真もダメだったすまん。



構成

2501Slave Client x N

Unity + WS


WebSocket経由でlua scriptを実行することができる。

デバッグ中のみ必要で、リリースビルドに含むと審査に落ちる。

2501(PuppetMaster) + Slaveyard Server

node


Clientの操作コンテキスト管理と、群体制御、結果/モニタリング機能を受け持つ。


ブラウザ

2501の挙動はブラウザから見れる。

また、ブラウザから群体/個体に対してluaその他で制御コードやbotを送り込むことができる。



できること

・群体制御/個体制御

・スクショ好きな時に/自動化

・スクリプト実行(履歴はGUIに持たせてもいいしサーバに持たせてもいいし

・Tail

・エラープルーフ(スクリプト実行エラーがでてもまあ端末は死なない

・ボット常駐

・現在のゲームのコンテキストに則ったメソッド実行

・実行可能メソッド抽出

・メソッド待ち構え処理



群体制御/個体制御

接続してる全端末に向けて処理を並列でぶっとばせる。

・自動的に適当な画面まで進む、とかができる。

・ある端末をリーダーにしてその端末と同じ処理を他の端末に流して同期とかできる。


スクショ好きな時に/自動化

低負荷かつ異様に高速なスクリーンショット。

ファイル吐き出し or DB

(ReactのUIに表示したかったがまにあわんかった)

SCREENSHOTボタン押す



スクリプト実行(履歴はGUIに持たせてもいいしサーバに持たせてもいいし

luaから端末内の制御メソッドを叩ける。


scriptは端末側の都合のいいタイミングで実行されるので、端末ごとの入力ズレはほぼない。

ちなみに全てのスクリプトは、coroutineとかを書かない限り同一のフレームで同期的に実行される。


coroutineとか書くとフレームをまたいで実行できる。

つまり適当なスパンで端末のメソッドを叩ける。


backbone.Screenshot()



Tail

端末全部に対してTailを仕掛けられる。

実際にはもっと頻度は低いので、負荷は低い。(頻度は指定できる


TAILボタン押して端末動かす

Titleで放置したり、遷移先でAとかボタン押したり。


エラープルーフ(スクリプト実行エラーがでてもまあ端末は死なない

まあはい。ゲームの邪魔はしない。



ボット常駐

定期イベントでなんかするbotとかを書ける。luaだし。

こないだMackerelのイベント行った時に面白かったんでパクった。



現在のゲームのコンテキストに則ったメソッド実行

ゲーム内のインスタンスをluaから実行できる。

例えば TitleScript型のインスタンスと、そのメソッド があったら、TitleScript.メソッド(引数) という記法でluaから実行できる。

引数があるメソッドもぶったたける。

これによって、uGUIとかUnityで主流なGUIのメソッドは、ほぼすべて裏側から叩ける。



実行可能メソッド抽出

現在のUnityのコンテキストで実行可能なインスタンス一覧と、

そのインスタンスが保有している実行可能な関数一覧を取得する。


(UIがアレなんだけどまあプレゼン。)

availables ボタン ->

backbone.ReturnAllAvailables("CameraScript")


この返り値が、このCameraScriptインスタンスで、現在実行可能なメソッド集。

availables.targetInstanceName:CameraScript methodSignatures:

Awake(),

BackToTitle(),

ButtonTapped(System.String key),

Invoke(System.String methodName, System.Single time),

InvokeRepeating(System.String methodName, System.Single time, System.Single repeatRate),

CancelInvoke(),

CancelInvoke(System.String methodName),

IsInvoking(System.String methodName),

IsInvoking(),

StartCoroutine(System.String methodName, System.Object value),

StartCoroutine(System.String methodName),

StopCoroutine(System.String methodName),

StopAllCoroutines(),

GetComponent(System.String type),

CompareTag(System.String tag),

SendMessageUpwards(System.String methodName, System.Object value),

SendMessageUpwards(System.String methodName),

SendMessage(System.String methodName, System.Object value),

SendMessage(System.String methodName),

BroadcastMessage(System.String methodName, System.Object parameter),

BroadcastMessage(System.String methodName),

ToString(),

GetInstanceID(),

GetHashCode(),

Equals(System.Object o),

GetType()

わんさか返してくる。で、これは全部実行できる。


試しにTailした上で、ButtonTapped(string)を実行してみよう。

CameraScript.ButtonTapped("hello, devices.")


Tail結果にログが出たはず。



メソッド待ち構え処理

特定のメソッドの実行まで潜伏、メソッドの実行をトリガーにluaを実行することができる。


(UIがないけどまあできる。)



インスタンスを沈める

Backbone.Regist 関数を使って、任意のinstanceをゲーム中に2501に登録、そのインスタンスのメソッドを

ある程度自由に実行できる。


具体的には、publicで引数が string/number/bool ほか なメソッドを、luaからナチュラルにぶったたける。


前提として、適度にUIのインスタンスを

Backbone.Register(this);// thisは、たとえば Title クラスのインスタンス。

とかで沈める。Awakeとかで沈めとくといいと思う。

ここを自動化するのは安全性の面から考えてない。


これで、uGUIのボタンの動作とかを、luaから

Title.GoToGame()

みたいな感じでぶったたける。


luaで実行できる利点

・クライアント内にluaコンテキストを持てる

状態保持でき、それがC#側に波及しない。サンドボックスからの制御になるので状態を捨てやすい。

・coroutineを使って、適当なフレーム遅延を引き起こした上でGUIが裏から叩ける

coroutine最高という気持ち







今回のGUI作成のよもやまばなし

超ひさしぶりにnode触る。


満たしてて欲しい要件は、

サーバ:

・ws接続とhttp接続を受ける(wsのためのhttp getとかはws側のライブラリで処理できるととても良い

・binary受け取れる

・メモリ上に画像バイナリガンガン格納する -> 適当なフォルダに吐く

・モニタはそれを取得、表示する

クライアント

・luaが動く(execute用途、bot用途


とかか。

React + node + Webpack + Material UIでやろう(死亡フラグ



ws使う

あ、FileServerみたいなのがある、、、まじか、、

開いて読むとこまではつかえたんだけどこれアップローダだな、要らね、、


とりあえず接続可能になるとこまでやろう。

-> 32ビット以上のサイズを受け付けられない。ああ、、


-> 単にリミットしてあった。スクリーンショットのサイズは必ず64bitあたりになるんで、まあ、はい。

解除してしまったところ動いた。

OK。



今回のGUI

適当にReactで作ってみた。めっちゃ勉強になった。



ちょっと試してみたい:http/2

node.js http/2



ちょっと試してみたい、grpc。

https://github.com/google/dorusu-js

https://github.com/grpc/grpc/tree/master/examples/node


wrote 2016/09/02 23:17:42

MoonSharp


概要

UnityでLuaが動かせるので、使ってみていた。

MoonSharp

http://www.moonsharp.org


使い方次第では綺麗に自分の足が消し飛んだりすると思う。

MODライクな使い方は考えていなくて、特にデバッグや自動テストのためのツールとして使おうと思っていた。


結果的には2501というプロジェクトでとても役になった。



ざっくりとできることまとめ

・luaをUnity上で実行できる

・実行するluaはstringからいける

・特定のlua実行コンテキストを持ち回すことができる

・実行コンテキストのluaテーブルを好きに書き換えることができる(!)

・インスタンスを渡すこともできるので、好きにメソッドが呼べる

・luaのコルーチンも使える



やりにくいことまとめ

・当然だけど複雑な引数を持つ関数は実行しづらい



逆引きっぽいコンテンツ

以下は、勉強しながら触ってたらいい感じに逆引きみたいになった学習ログ。



staticな実行コンテキストでluaを実行する

luaの中で定義した関数をluaの中で実行し、結果をC#側で得ることができる。


double MoonSharpFactorial()

{

string script = @"    

-- defines a factorial function

function fact (n)

if (n == 0) then

return 1

else

return n*fact(n - 1)

end

end


return fact(5)";


DynValue res = Script.RunString(script);

return res.Number;

}



Scriptの実行コンテキストを保持する

実行コンテキストはstaticではなく生成できる。


double MoonSharpFactorial()

{

string scriptCode = @"    

-- defines a factorial function

function fact (n)

if (n == 0) then

return 1

else

return n*fact(n - 1)

end

end


return fact(5)";


Script script = new Script();

DynValue res = script.DoString(scriptCode);

return res.Number;

}



Luaコードのコンテキストに干渉する

変数の値とかに干渉できる。


double MoonSharpFactorial()

{

string scriptCode = @"    

-- defines a factorial function

function fact (n)

if (n == 0) then

return 1

else

return n*fact(n - 1)

end

end


return fact(mynumber)";


Script script = new Script();


script.Globals["mynumber"] = 7;


DynValue res = script.DoString(scriptCode);

return res.Number;

}


global値に干渉できる。

唐突だな~~。



特定のメソッドを呼ぶ

DoStringで評価してから、Call関数で関数名を指定して引数を渡す、ってことができる。


double MoonSharpFactorial2()

{

string scriptCode = @"    

-- defines a factorial function

function fact (n)

if (n == 0) then

return 1

else

return n*fact(n - 1)

end

end";


Script script = new Script();


script.DoString(scriptCode);


DynValue res = script.Call(script.Globals["fact"], 4);


return res.Number;

}



DynValue型は関数ポインタとして取り出せる

別にC#側から自由に呼べるわけではない。

単にポインタとして保持できる、っていうだけ。

double MoonSharpFactorial()

{

string scriptCode = @"    

-- defines a factorial function

function fact (n)

if (n == 0) then

return 1

else

return n*fact(n - 1)

end

end";


Script script = new Script();


script.DoString(scriptCode);


DynValue luaFactFunction = script.Globals.Get("fact");


DynValue res = script.Call(luaFactFunction, 4);


return res.Number;

}



DynValueはTuple型にもなれる

要素が三つのTupleで、indexアクセスができる。


DynValue ret = Script.RunString("return true, 'ciao', 2*3");


// prints "Tuple"

Console.WriteLine("{0}", ret.Type);


// Prints:

//   Boolean = true

//   String = "ciao"

//   Number = 6

for (int i = 0; i < ret.Tuple.Length; i++)

Console.WriteLine("{0} = {1}", ret.Tuple[i].Type, ret.Tuple[i]);



関数を渡せる

luaの中の関数定義を書き換えることで、C#の関数をluaから呼ぶことができる。

かなり無理やり。


private static int Mul(int a, int b)

{

    return a * b;

}


private static double CallbackTest()

{

    string scriptCode = @"    

        -- defines a factorial function

        function fact (n)

            if (n == 0) then

                return 1

            else

                return Mul(n, fact(n - 1));

            end

        end";


    Script script = new Script();


    script.Globals["Mul"] = (Func<int, int, int>)Mul;


    script.DoString(scriptCode);


    DynValue res = script.Call(script.Globals["fact"], 4);


    return res.Number;

}



置き換えなしにC#のメソッドを呼ぶ

特定のAttrを付けたクラスのメソッドを、Luaから呼び出す。

下記の例だと、MyClass クラスのcalcHyptenuseメソッドを、名前ベースでluaのグローバル変数にバインドすることなく呼び出している。


・実際にはUserData.RegisterAssemblyというメソッドでバインドしている。

・クラスのインスタンスはバインドしてる

とかがある。

これstaticにしても呼べるのかな?


[MoonSharpUserData]

class MyClass

{

public double calcHypotenuse(double a, double b)

{

return Math.Sqrt(a * a + b * b);

}

}


double CallMyClass1()

{

string scriptCode = @"    

return obj.calcHypotenuse(3, 4);

";


// Automatically register all MoonSharpUserData types

UserData.RegisterAssembly();


Script script = new Script();


// Pass an instance of MyClass to the script in a global

script.Globals["obj"] = new MyClass();


DynValue res = script.DoString(scriptCode);


return res.Number;

}



Attrつけなくても、クラス個別で受け付ける方法

クラスインスタンスに対して、thisとかも使えるのを確認した。


class MyClass

{

public double CalcHypotenuse(double a, double b)

{

return Math.Sqrt(a * a + b * b);

}

}


static double CallMyClass2()

{

string scriptCode = @"    

return obj.calcHypotenuse(3, 4);

";


// Register just MyClass, explicitely.

UserData.RegisterType<MyClass>();


Script script = new Script();


// create a userdata, again, explicitely.

DynValue obj = UserData.Create(new MyClass());// この部分thisでもいける。

script.Globals.Set("obj", obj);


DynValue res = script.DoString(scriptCode);


return res.Number;

}



luaからstaticなメソッドを呼ぶ

いくつか方法があるが、以下が楽。


double MyClassStaticThroughPlaceholder()

{

string scriptCode = @"    

return obj.calcHypotenuse(3, 4);

";


// Automatically register all MoonSharpUserData types

UserData.RegisterAssembly();


Script script = new Script();


script.Globals["obj"] = typeof(MyClassStatic);// Set関数は使えない。


DynValue res = script.DoString(scriptCode);


return res.Number;

}



使用感

2501では、これらを利用して、lua沼にbackboneというデバッグ用にnewしたインスタンスを沈めていた。

するとluaからbackboneのインスタンスとそのpublicメソッドがぶったたけるので、とても便利、っていう。

メモリ計測、ログ送付、スクリーンショット送付とかをやっている。


さらに、ユーザーのインスタンス(実行中のみ存命なインスタンス)を沈めることで、外部からリアルタイムでのメソッド着火を可能にしている。

これはとても柔軟で、登録されているaliveなインスタンス一覧、またpublicかつluaから渡せるインスタンスで動かせるメソッドを全部実行可能。








wrote 2016/09/01 17:39:26

DisqueのTTLとRetryについて


概要

TTLとRetry組み合わせた際の挙動がよくわかってなかったのでメモっておく。


Disqueはなんか分散ジョブキュー。

Disque

https://github.com/antirez/disque


使ってるクライアントは自作のDisquuun。

Disquuun

https://github.com/sassembla/Disquuun



TTL

Time To Live なのでDisque-serverに登録したジョブの生存時間。

Disqueの場合はAddJobコマンドのオプションでジョブ追加の都度指定する。


Disquuunの場合だと次のようなコードになる。

disquuun.AddJob("queueName", new byte[]{0,1,2}, 0, "TTL", 1);

TTLの単位はsecなので、これでDisque-server側にこのジョブは、ジョブがキュー"queueName"に追加されて1秒経つと消滅する。

ただし、デフォルトのDisqueの設定だと、こういったタイマーに関する分解能が10hz(秒間10回)程度になっているので、わりとやんわりとした動作になっている。


ちなみにTTLを指定しなかった場合のデフォルト値は 1day = 86400sec とか。


Retry

リトライ、なんかちゃんと向き合っていなかったのだけれど、

Retry値は、GetJobされたジョブが、再びキューに入るまでの時間を指定するパラメータになっている。


指定はDisquuunの場合だと次のようなコードになる。

disquuun.AddJob("queueName", new byte[]{0,1,2}, 0, "RETRY", 1);



この辺の挙動はテストケース書いたんで具体的にこうなるんだぜみたいな例がある。

https://github.com/sassembla/Disquuun/blob/master/DisquuunTest/Tests_1.cs#L64


Retryの値に関する仕様は以下のようになってるらしい。

・デフォルト値は5分

一度GetJobされてから5分経ったら、再装填が発生する。


・0ならば"最大で1回送付"モードになる

んでGetJobが発生したら実際にどうなるの?っていうと、これが面白かったので後述する。


・0より大きい数値ならば単位はsecで、この秒数が過ぎたら再装填が発生する

この値の指定と効果には特例があって、


TTLが指定してあり、かつ、TTL x 0.1(sec) < RETRY指定値(デフォの場合は5min)の場合、RETRY値はTTL x 0.1(sec) に指定される。

例えばTTLを5分にした場合、5x60sec(TTL) x 0.1 < 5x60sec(RETRY) なので、RETRY値は自動的に 5x60sec(TTL) x 0.1になる。


なにがなんでもRETRYさせたいらしい。まあ明示的に指定してるんだしな。



最大で1回送付 モードになるって実際にはどういう挙動なの?

ここまでで、TTLでジョブの寿命が、Retryでジョブの再装填が制御できることがわかった。

で、例えば次のような指定をした場合どうなるのか。

case1.Retry = 0

case2.TTL = 10sec

case3.Retry = 0 + TTL = 10sec



case1.Retry = 0

Retryが0なので、GetJobしたらackしないでも二度とキューに現れない。

ジョブ自体はどうなっちゃうんだろう?


var len0 = DisquuunDeserializer.Qlen(disquuun.Qlen("queueName").DEPRICATED_Sync());

このlen0は確かに0になる。


が、


var info = DisquuunDeserializer.Info(disquuun.Info().DEPRICATED_Sync());

var restJobCount = info.jobs.registered_jobs;


infoから取得するrestJobCountは、これなんと1件になる。

残っとるんかワレ。しかも二度と"queueName"には登らないだと、、、


別にRetry = 0時のみの特殊な挙動ではなくて、

Retryの値がなんであれ、例えばRetry指定をしてない場合は、

・5分経つまでキューの外で待つ(qlenは0を返す

・じゃあどこにいるの、っていうと、Infoでは見えるどこかにいる

という挙動になるみたいだ。


ちなみにRetry = 0だと、再装填は発生しない + TTL未指定なので、TTLデフォルトの1日が経過するのを待って死ぬ感じ。



case2.TTL = 10sec

Retryがデフォ5min -> TTLの10%より小さいので、RetryはTTLの10% = 1secになる。

つまりGetJobとかが発生すると、1秒で復帰してくる。


Disqueのフレームレートがデフォルト10hzなので、まあ10秒間の寿命の中できっちり10回再装填されることは無いと思うけれど、

なるほど1秒で再装填されるのか、、と思うと感慨深い。



case3.Retry = 0 + TTL = 10sec

というわけで、Retryを明示的に0にセットし、TTLを10secにした場合、

・ジョブは一度GetJobされたりすると、キューからは外れる

・Retry = 0なので二度とキューに再装填されない

・TTLが10secなので10秒したら死ぬ

というのが起こる。



以上。






wrote 2016/08/30 1:20:57

コントラスト


概要

・一定の変化速度で変化するものは大きなコントラストを感じられない

・コントラストの差がでるところ、上限と下限をたくさん用意して、その差が最大になるようなところをクライマックスに持ってくる



アクション、パズル、リソース、官能、運

格ゲーとかだとアクション主体に他の要素が絡む

将棋だと、パズル、リソースを主体に他の要素が絡む



幅、深さ

幅:ボリュームの多さ


深さ:プレイバリュー、戦術の価値の高さ



ゲームにメリハリを持たせる

リスク & リターン



マリオ

リスク&リターンの幅を広げるBボタン

緊張感と達成感につながっている。



ゲームの手応えを作る

= リアクション

ダメージリアクションのコントラストをどのくらい巨大にするか。


アクション3割、リアクション7割くらいという体感。



時間に関するコントラスト

速度のコントラスト

インベーダーゲーム、最後高速になる。


時間差のコントラスト

ボンバーマンの爆弾

読み合いが生まれる。



クロスワードにおける試行錯誤と結果

クロスワードだと、正誤に関する情報が、ゲーム中での感情の変化につながる。

パズルでは、「解き味」と呼ばれるパラメータ。



リソース

戦術、戦略を作り出すために、


「2倍になってるんだから2倍面白いでしょ」そんなことはなくて。


3すくみ

パラメータを色として捉えて、色相のように考えてみる

グー、チョキ、パー 強いグー、チョキ、パー


プロトタイプを作って確かめる。



レベルアップ

今自分が作っているゲームは、強さの変化をアナログ(グラデーション)なのか、レベルアップ(階段)で表したいのか。



浸りで遊ぶサイコロゲーム

どちらかが1を出したら勝ち <- 不思議と面白い。


なぜ運ゲーなのに面白いと感じるのか



4種のフィードバック

ポジティブ

目的達成


ネガティブ

目的失敗


ニュートラル

どちらでもない


反応がない

ない


→後知恵バイアス(過去起こったことは予測できる)みたいな錯覚のせいで、先ほどのサイコロゲームがおもしろく感じられる。



成功を輝かせるための、失敗のコントラスト











wrote 2016/08/25 14:57:06

アナログゲームのデジタル性


わかりやすさを作るためのノウハウ



言語に依存しないアイコン

言葉を使わない、、、アレ、、、



知見の共有

題材ありきのテーマに即したゲームを作るとき:ウォーゲームの知見が合うかも。(題材ありきなんで。



プレイヤーの立場を定義

自分が何者か、を明示する。

視点のブレを防ぐ。


観客という定義にすることができる



誇張と省略

プレイヤーの立場とのリンクを考える。

粒度とか。

立場を弱めるようなデザインは避けたい。


コンピュータが自動的に処理する、っていう事態を使って、省略ができる。

→過度な省略はゲームの寿命を縮めることができてしまう。


すべてのシステムに意味を

ダメージが乱数になる武器 -> 当たりどころが違って、、とか

なぜらんすうを使うのか

より小さい仕様で、より大きな内容を含ませることができる。


意味を持たせることができる が。

ブラックボックスになっちゃうので、埋めすぎないほうがいい


意味のないシステムは使われない。



プロトタイプから固有名詞を使う

名前で表示できる要素がある。

戦艦 -> ヤマトならヤマトって書いとかないと。

なぜ -> その表示だけで


緻密なシステムで正確に表現できるとしても、正確さを表すことが力を発揮しないのであればしょうがない。


コアになるシステムがある程度以上複雑でないと、経年に耐えられない

wrote 2016/08/25 13:37:13

buildMapを使ったAssetBundleBuildについて


概要

AssetBundleを組み立てる方法として、buildMapってのがある。

簡単に言うと、arrayでAssetBundleの指定ができる。


AssetBundleBuildインスタンスにはstring assetBundleNameと、string assetBundleVariant、string[] assetNamesという3つのプロパティがある。



mapping

こんな書き方ができる。

var buildMap = new AssetBundleBuild[2];


// set bundle name and contained contents to map for No 0.

{

var bundle_0AssetPaths = new string[1];

bundle_0AssetPaths[0] = "Assets/scr1.png";


buildMap[0].assetBundleName = "bundle_0.assetbundle";

buildMap[0].assetNames = bundle_0AssetPaths;

}


// No 1.

{

var bundle_1AssetPaths = new string[1];

bundle_1AssetPaths[0] = "Assets/scr2.png";

buildMap[1].assetBundleName = "bundle_1.assetbundle";

buildMap[1].assetNames = bundle_1AssetPaths;

}


BuildPipeline.BuildAssetBundles("somewhere", buildMap, BuildAssetBundleOptions.None, BuildTarget.iOS);



使い所

BuildAssetBundle()の代わりに、単体でAssetBundleを作るのにつかえそうな気がする。

BuildAssetBundle()さんが死亡したんで、使えると嬉しいが、Push, Popに相当するものはあるんだろうか。

-> なさそう



依存関係とかはどうすれば良いんだろう? -> 指定して実行してみた


var buildMap = new AssetBundleBuild[3];


// set bundle name and contained contents to map for No 0.

{

var bundle_0AssetPaths = new string[1];

bundle_0AssetPaths[0] = "Assets/scr1.png";


buildMap[0].assetBundleName = "bundle_0.assetbundle";

buildMap[0].assetNames = bundle_0AssetPaths;

}


// No 1.

{

var bundle_1AssetPaths = new string[1];

bundle_1AssetPaths[0] = "Assets/scr2.png";

buildMap[1].assetBundleName = "bundle_1.assetbundle";

buildMap[1].assetNames = bundle_1AssetPaths;

}


// No 2. depends on same asset in No 0 and 1.

{

var bundle_2AssetPaths = new string[2];

bundle_2AssetPaths[0] = "Assets/scr1.png";

bundle_2AssetPaths[1] = "Assets/scr2.png";


buildMap[2].assetBundleName = "bundle_2.assetbundle";

buildMap[2].assetNames = bundle_2AssetPaths;

}


BuildPipeline.BuildAssetBundles("somewhere", buildMap, BuildAssetBundleOptions.None, BuildTarget.iOS);


青、オレンジそれぞれが同じAssetを指している。

たぶんindexの若い順に解決されて、後半のものが依存になるのでは?


→実行時にエラーが出る。

Asset "Assets/scr1.png" has been marked into more than one AssetBundles.

UnityEditor.BuildPipeline:BuildAssetBundles(String, AssetBundleBuild[], BuildAssetBundleOptions, BuildTarget)


この方法では、ひとつのAssetは一つのassetNamesに対してしか登録できず、依存は書けないっぽい。



解決法

buildMapを使った場合の依存の書き方はなくって、

依存は勝手に解決される、というのが答えだった。


概念的には、

・依存は勝手に解決される

・オリジナルを明示することはできないので、どこに依存Assetが入るかを指定する方法はない


という感じだった。


具体的な例を用意中。






wrote 2016/08/22 15:13:26

薄味オープンソースフレームワーク Autoya


概要

雑に認証とか通信とか動くものをこしらえて本当にがんばらなくてよくなりたかった。

Unity製。

サーバ側はRustで書かれているよ。


Autoya

https://github.com/sassembla/Autoya



頑張らなくて済むもの

・初回起動時認証->トークン取得

・トークンで認証

・課金のベーシックなフロー

・横断的なエラーハンドリングバックボーン

・リアルタイムエラーロギング (Slackに打ち込んだりそういうの



とかが、勝手に起動されて、例えば認証済みのHTTPがこんな感じに使えるようになる。

HTTP Get

https://github.com/sassembla/Autoya/blob/master/Assets/AutoyaTests/Editor/Tests/AuthorizedHTTPImplementationTests.cs#L15

var connectionId = Autoya.Http_Get(

"https://httpbin.org/get", 

(string conId, string resultData) => {

result = "done!:" + resultData;

},

(string conId, int code, string reason) => {

// do nothing.

}

);



別の意味で頑張らなくて済むもの

インストール。


このフレームワークはUnityの

RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)

Attributeを使っているので、AssetsフォルダにAutoyaフォルダを入れたらすぐに認証とかが走るようにできる。

https://github.com/sassembla/Autoya/blob/master/Assets/Autoya/Backyard/AutoyaEntryPoint.cs#L11



ToDo

サーバ側のAPIのリファレンス書かねば



wrote 2016/08/10 13:01:39

UnityのNetworkのアレ、UnityWebRequest


概要

UnityWebRequest

https://docs.unity3d.com/Manual/UnityWebRequest.html

WWWのリプレースができる、WWWよりまともな通信機能。


公式で日本語な資料

http://docs.unity3d.com/ja/current/Manual/UnityWebRequest.html



AsyncOprerationまわり

素朴な疑問として、

WebRequestの実行をすると、AsyncOperation型のインスタンスを返してくるんだけど、

C#でのAsyncOperation

https://msdn.microsoft.com/ja-jp/library/system.componentmodel.asyncoperation(v=vs.110).aspx


vs


UnityでのAsyncOperation

http://docs.unity3d.com/jp/current/ScriptReference/AsyncOperation.html


全然別の同じ名前のやつだった。完。



AssetBundleのキャッシュとか関連はどうなってるの?

キャッシュは使える。指定するパラメータがversion(実際には相変わらずversionではない)、Hash128のどちらかを使える。




wrote 2016/08/01 2:02:21

Unity Editor上で非同期テストしたいからMiyamasuっての作った


概要

5.3からテストユニット入ってたのガン無視してテストツール自作してた。


理由はまあCoreCLRでも動く非同期/同期待ちを頑張ったやつが使いたかったからなんだけど、

Unity5.3から標準でNUnit入ってるんでじゃあどっちでも使えば良いじゃんってなってやっと手をつけた。


んだけど、今組み込まれてるテストツールでも単体だとまだ非同期のテスト書けねえのな、、がっかり。


結局自作したテストツール整備してたら公開できる感じになったのでそんだけ。


エディタでだけでもasync使えれば

って思ってたんだけどまだダメみたいだな、、まあいいや。


というわけで、アノテーション書けば適当に依存なしでUnityからCoreCLRまで一貫して動く自作してたやつを書いた。

Annotation絡みの実装を一回やってみたかったっていうのもある。

急いで作って急いで使って、Editorでasyncが書けるようになったら捨てる。

Miyamasu

https://github.com/sassembla/Miyamasu


次のようなコードで非同期の結果を待てる


[MTest] public void SampleSuccessAsync () {

var done = false;


/*

the sample case which method own their thread and done with asynchronously.

*/

{

var endPoint = new IPEndPoint(IPAddress.Parse("0.0.0.0"), 80);


var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

var connectArgs = new SocketAsyncEventArgs();

connectArgs.AcceptSocket = socket;

connectArgs.RemoteEndPoint = endPoint;

connectArgs.Completed += new EventHandler<SocketAsyncEventArgs>(

(obj, args) => {

// failed or succeded, done will be true.

done = true;

}

);


// next Async operation will be done really soon in async.

socket.ConnectAsync(connectArgs);

}


        /*

wait while 1st parameter "Func<bool> isCompleted" returns true.

in this case, "done" flag become true when async operation is done.


2nd parameter "1" means waiting 1 seconds.

        */ 

      WaitUntil(

() => done, 

1

);

}

WaitUntil(Action<bool> waitFor, int waitSeconds)行が面白いところで、この行で条件付きの待ちを行っている。

この時の条件は、doneがtrueになるまで1秒間待つ、というもの。



MainThreadでしか実行できない要素をテスト

こんな感じに書ける。

[MTest] public void SampleSuccessAsyncOnMainThread () {

var dataPath = string.Empty;


/*

sometimes we should test the method which can only run in Unity's MainThread.

this async operation will be running in Unity's Main Thread.

*/

Action onMainThread = () => {

dataPath = UnityEngine.Application.dataPath;// this code is only available Unity's MainThread.

};


RunOnMainThread(onMainThread);


/*

wait until "dataPath" is not null or empty.

*/ 

WaitUntil(() => !string.IsNullOrEmpty(dataPath), 1);

}


RunOnMainThread(Action)っていうメソッドで、特定のコードを特定の順でほぼMainThread(実際にはUnityEditorのupdate)で実行できる。

上のテストは、Action onMainThreadをMainThreadで実行し、その実行が終わるまでの間、WaitUntilで待つ。



画像は最近宮益坂にできたコメダの宮益坂 ミックスサンド

名前に悩んでたらちょうどこれ食ってたのでMiyamasuにした。

IMG_1646.JPG


美味しいが馬鹿でかい。

写ってる部分で全体の半分くらい。


2人分くらいある。これで770円は安い、、、



wrote 2016/07/31 14:43:38

UnityとCoreCLRのはなし


概要

Unibook振り返り+夏のLT大会!

http://eventdots.jp/event/593863


LTで申し込んだと思ってたら違ってた。しまった、、

隙があったのでやって良いとのことなんで代打。


プレゼンモードはこちら

https://dl.dropboxusercontent.com/u/36583594/outsource/UnityAndCoreCLR/index.html



DotNet Core

C#の最新バージョンがMacとかLinuxとかWindowsで動く



最新?

Unityで使ってるC#はDotNet3.5をMonoが実装したやつをUnityがさらに独自のセンスでチョイスしたやつ


DotNet 3.5 Unity ver

・mscorlib.dllっていうごった煮dllで動いてる。

Macだと、実体はUnity.appのフォルダの中のこのへんのどれか

・シングルスレッドで動かしたり、IEnumeratorでコルーチン使って動かす分にはまー問題ない

・反面、例えば通信とかでマルチスレッドにしたりとかメインスレッドに合流したりとかが面倒

頑張って実装した猛者とかもいる

Spicy Pixel Concurrency Kit https://www.assetstore.unity3d.com/en/#!/content/3586

UniRx https://www.assetstore.unity3d.com/jp/#!/content/17276

・メインスレッドで動作することを完全に放棄してマルチスレッドの化け物になった猛者とかもいる(それでも動く

AnotherThread https://github.com/unity3d-jp/AnotherThread

対して、DotNet Core は


DotNet Core

https://github.com/dotnet/coreclr

・言語的にはC#の最先端、DotNet 4.6

・mscorlibの代わりにcorefxっていう完全新作ライブラリ群を使う。

どのくらい完全新作かというと一部C#2.0とかで足されたものを抹消して全プラットフォームごとに別実装対応 + あわせてインターフェースかわるくらい新作

・Taskっつーのがあって便利

・いろんなプラットフォームでコンパイルできる



例えばどんな差があるの

Socket(TCPとかを扱う低レベルAPI)の切断用のAPIが 10個以上 -> 1個 になったりした。

かっこいい、、、、!!!


UnityもDotNet Foundation に入ったんで、そのうちCoreCLRとかベースで動くようになる? のか??

Unite Tokyo会場で聞いた時にはまずC#5.0、その後C#6.. みたいに対応するよって言ってた。

待ってればいいんだよな~~っていう。



今できることは?

DotNet Coreが出たことで、クライアントもサーバもC#で書ける

→やってみたい、、、やってみたくない、、、?



できたよ?


リアルタイム対戦ゲーム


1 vs 1 

1台 500円/月レベルの信じられない低スペックサーバで数百人まで同時接続可能

全部C#

クライアント:Unity

サーバ:DotNet Core 1.0



全部C#の利点って?

例えばゲームロジックをクライアントとサーバで共有できる

Unity独自のAPIを使わない前提

自分で簡単な判定ロジック作って使ったりとか


データ構造の定義を完全共有できる

クライアント -> サーバへとデータ送るじゃないですか。


その時のデータ形式、例えば

クライアント = Unity内で、クラス -> インスタンス -> JSON とか変形するじゃないですか。


受け取った側(サーバ)でも

サーバ = DotNet Core内で、JSON -> インスタンス -> クラスとか変形したいですよね。


ようはクラス定義の.csをクライアント <-> サーバで貫通させたいよねっていう。


これできると楽です。


速い

ぶっちゃけソケット周りの動作に関してはWindowsで動かすよりLinux/Mac上で動かしたほうがえらい高速な気がしている。

動作速度速い。かつ、恐ろしい環境でもかなり安定して動作する。


(もう3~4ヶ月動かしてるけど変なエラーに出会えない)



っていうか

1つのまともな言語でサーバとクライアント両方書けて(かたっぽはまだDotNet3.5っていう古代魚だが)

コンパイルがあってMacでもLinuxでもWindowsでもネイティブ吐き出しができて、かなり良い速度で動かせる言語+環境になってしまったのでは....?



調整中で公開できるもの

XrossPeerっていう、

クライアント:Unity

サーバ:DotNet Core 1.0


とかを可能にするツール。


checked it out!

1つのプロジェクト内でCoreCLRのビルドとUnityのビルドを共存させる

http://sassembla.github.io/Public/2016:07:05%2015-57-53/2016:07:05%2015-57-53.html


XrossPeer

https://github.com/sassembla/XrossPeer


wrote 2016/07/23 12:18:44

OpenSourceになってるCoherentUI1.xをとりあえずUnity5系で動かす


概要

2系はなんか欲しいものから違う気がしたので、オープンソースになってる1.xについて、view-touchインターフェースの部分だけ追おうと思った。

環境は

Mac OS X 10.11.15

iOS 9.3.2

Unity 5.4.0 f1



欲しいのは

・任意のViewをテクスチャに変換する機構

・テクスチャに対してタッチとかをイベントとして伝達する機構

の2つ。


結論から言うと動かせたんだけど「これじゃねーな」って感じがしたんでCoherentからは撤退する。



インストール

Unityに入れて動かす前に、pythonでビルドする必要がある。


Macで実行するとiOS版、Winで実行するとAndroid版が作られるみたいだ。

超過渡期の産物の匂い。


で、swigがpcreに依存してたりする。入ってねーっつーの。


### SWIG error output:

dyld: Library not loaded: /opt/local/lib/libpcre.1.dylib

  Referenced from: /Users/tartetatin/Desktop/CoherentUIMobileOpenSource/Tools/DotNETWrapperGenerator/swig-2.0.9/swig-ios

  Reason: image not found



brew install pcreで、適当に入れて動かしてみる。

で、下記行あたりでひっかかる。



subprocess.check_call(['/Applications/Xamarin Studio.app/Contents/MacOS/mdtool',

                 'build', projectPath, '-c:Release'])

Xamarin要るんかワレ。ほお、、、


で、本当に使っているのかなこれ?っていう。一応避けて(コメントアウトして)ビルドすると、Swig自体は動いたようで、ビルド成功してライブラリいっぱい吐いていた。

なるほど。スキップしちゃったんだけどこれmdtoolないと正しく動かない気がするな。



いろんな行の意味を追う


    subprocess.check_call(

        ['python', 'Src/DotNet/MobileNet/ReplaceHandleRefForIOS.py', '--base', '.'])

参照の書き換えをやってるみたいな。C#コードを直にいじってるのかな。

いろいろ置換してるっぽい。


subprocess.check_call(['/Applications/Xamarin Studio.app/Contents/MacOS/mdtool',

                 'build', projectPath, '-c:Release'])


ここでは、projectPathに置いてあるC#コードをビルドしてるっぽい。なんでだろって思ったけど置換まわりと関係がありそう。

なるほどな~~Xamarinのmdtool依存決定的っぽい。


Xamarin入れた上でmdtoolを使って複数のコードからdllが作れた。


そのdllにいろいろ含まれてて、それを使ってUnity側のビルドが通るとかを確認した。


で、このdllを作る工程を無視したい。


projectPathは、

Src/DotNet/MobileNet/CoherentUIMobileNetIOS.sln

なので、まあその中身を使えばいいのです。


実機で動かす

動かせると思うところまで来た。組み合わせ問題(ライブラリと.aオブジェクトの対応問題)が各アーキテクチャで出るので、ビルドするところも自動化しておかないとな~みたいな感じになる。


問題

__ZN13ScreenManager12SetupDisplayEi


Simulatorの場合、ビルド時にぜったいうまく動いてない感がある。

実行時にこいつがないって言われる。


Deviceの場合、そもそもビルドに失敗する。

なんの条件があるんだか、、、


Deviceでビルド通したほうがいい気がする。



デバッグビルドでDevice

「ビルドの度に元プロジェクトを消す」

ってやったらうまくいった。謎い。再現しよう。



サンプルについて

MobileInputは、viewをカメラ前に展開して、それがオブジェクトへのインプットを制御するっていう系統。

HTMLで作ったUIをカメラ前面に展開して、その状態をブラウザが保持、イベント伝達のオン/オフ切り替えと、実際にオン && ビュー上のオブジェとUIの重なってる領域をタップしたらオブジェが動く、とかをやってのけている。


カメラに張り付いているビューは、CoherentUIView.csをカメラインスタンスにくっつけたもの。こっちにはInput要素の扱いがあり、

Take All | Take None | Transparent の三択。


Take All だと吸収して貫通させない、 Transparentだと吸収せず通過させる、みたいな感じかな。

カメラに張り付くんじゃなくてオブジェクトに張り付いて欲しいんだが。



で、もう一個のサンプル MobileSurface.unity のほうでは、回転するペラ1のテクスチャにブラウザの画像を出していた。


MobuleSurfaceView.csを起点にして、テクスチャをサーフェスに貼るってことで動作してるみたいだ。

内部で使われてるのはMobileSurfaceView。

で、なんでかレンダラの参照が切れてて、それを指定しないといけない。動く組み合わせを見つけた。


このスクリプトに対して、

GUIにしたかったんだけど、表示されるだけでインプットを受け付けてくれない。ので、前出のCoherentUIViewが物体に貼り付けられればそれで良い感じ。



クラス

CoherentUIView.cs

MobileSurfaceView.cs


の二択になっていて、前者はそのままカメラを探して乗っ取るみたいなことをしてる。



結果

GUI表示しつつ適当なキューブ(回転する)の上にタッチ反応するWebView置けた。

IMG_1576.PNG

依存分解

欲しいものは、


これ、依存を分解していくと、

・dll

・iOS用の.aファイルに依存(ここは結局独自のWebView実装を持ってないみたい。各プラットフォームのものを使っている?)

・mmファイル一個をPluginに置くことでUnityとWebViewをリンクさせてる


とかなんで、dllはまあC#のコードに分解できるとして、そっから先だな~~ .aファイルの負ってる役割の部分はこれこのままやるにはすごく辛い予感。



一応代替案がみつかったので動かしてみる


CEF3とそのMono用のラッパー。

https://github.com/cefsharp/CefSharp

https://bitbucket.org/xilium/xilium.cefglue/wiki/Home


ぶっちゃけChromium動かせるならそのほうが良い。

ポイントとタッチはどうやってるかわかったんで、まあ積めば良いよねっていう。



資料

http://klabgames.tech.blog.jp.klab.com/archives/1051659722.html

http://www.insaneunity.com/blog/2014/02/14/more-on-wtw-ui-cef3-integration/



ほか

https://github.com/jdierckx/UnityBerkeliumPlugin

https://github.com/sepehr-laal/UnityChromiumPlugin



wrote 2016/07/17 14:12:14

VSCode+UnityでC#1.2.2入れると補完とか出なくて詰むのを回避する


概要

VSCode 1.3系になってから、C#のプラグインも更新された。

で、これを使うと、Unity + VSCodeで補完が出ない。

そういや誰か言ってたよな~~ってなりながら、公式のリンクがミスっていたので、ハマってた。



症状

・VSCodeにて、C#プラグイン1.2.2をインストールする

・Unityのプロジェクトを開いて編集しようとする

と、C#の補完が全く効かなくなる。



原因

VSCodeのC#プラグインが1.2になって、Breaking Changeがあった。

1. .NET Core 1.0がリリースされたのでそれを使っている、RC1とか2の頃のやつはアップデートしてくれ

2. Mac, Linux上で、.csproj 形式のファイルを読み込んでの補完がすごく限定的になっている。問題なのは認識しててすぐ直すんで、今すぐ何とかしたい人はレガシー版を使ってくれ。


2が致命傷になっている。



対処

ってことで、なんだレガシー版入れればいいじゃんってなるんだけど、

そのレガシー版のプラグインのURLが間違ってるIssue上げといた。


そのままVSCode上のURL開くとこうなる。

スクリーンショット 2016-07-11 11.41.28.png



おまえ、、!! おまえおまえ、、!!!



レガシープラグインの誤ったURL

https://marketplace.visualstudio.com/items?itemName%3Dms-vscode.omnisharp

URLに直にBase64Encodeしたのを入れてるみたいだ。



レガシープラグインの正しいURL

https://marketplace.visualstudio.com/items?itemName=ms-vscode.omnisharp


スクリーンショット 2016-07-11 11.42.01.png


ということで正しいURL使ってインストールすると動くよって感じだった。



追記

2016/07/21 16:46:33

VSCodeのrepoにIssue立てといたら、1.3系で治せると思うから待っててね! ってコメントついてたんで、1.3系のリリース待ってると良いと思う。

1.2.xしか出てなくてでもコード書かなきゃ、、っていう時でどうしようもなかったらまあ頑張ろう。


wrote 2016/07/11 11:39:50

CoreCLRで遭遇する楽しいエラーというか滅ぼされたものとかと戦う


概要

思ったよりエラーが秩序立って出るのでコレクションしてみた。


使ってる基本ライブラリはこれ。

https://dotnet.github.io



対して、実装している対象はこれ。

Disquuun

https://github.com/sassembla/Disquuun



環境

MacとかUbuntu14とかがメイン。だって確認が簡単なんだもん。

サーバで動く.Net Coreは良いぞ。



遭遇したエラーとかを列挙していく。



いまのところ一番凶悪なエラー Could not load file or assembly 'System.Diagnostics.StackTrace

Unhandled Exception: System.IO.FileLoadException: Could not load file or assembly 'System.Diagnostics.StackTrace, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. A device attached to the system is not functioning.

 (Exception from HRESULT: 0x8007001F)

   at System.RuntimeTypeHandle.GetTypeByName(String name, Boolean throwOnError, Boolean ignoreCase, Boolean reflectionOnly, StackCrawlMarkHandle stackMark, IntPtr pPrivHostBinder, Boolean loadTypeFromPartialName, ObjectHandleOnStack type, ObjectHandleOnStack keepalive)

   at System.RuntimeTypeHandle.GetTypeByName(String name, Boolean throwOnError, Boolean ignoreCase, Boolean reflectionOnly, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean loadTypeFromPartialName)

   at System.RuntimeType.GetType(String typeName, Boolean throwOnError, Boolean ignoreCase, Boolean reflectionOnly, StackCrawlMark& stackMark)

   at System.Type.GetType(String typeName, Boolean throwOnError)

   at System.Diagnostics.StackFrameHelper.InitializeSourceInfo(Int32 iSkip, Boolean fNeedFileInfo, Exception exception)

   at System.Diagnostics.StackTrace.CaptureStackTrace(Int32 iSkip, Boolean fNeedFileInfo, Thread targetThread, Exception e)

   at System.Exception.get_Source()

   at System.Exception.InternalPreserveStackTrace()

   at ServerInitializer.Init()

   at ConsoleApplication.Program.Main(String[] args)


わけがわからないときにでる。内容は、StackTraceの入ってるassemblyが読めない、っていうことを言われて、は?ってなるっていう。

端的に言うとこれをひいた。

Exception stack is bogus when ulimit is hit. #5782

https://github.com/dotnet/coreclr/issues/5782

場所がさっぱりわからないことになる。

あっちなみにこのエラーが出ると、プロセスが落ちる。



StackTraceよもやま話

stacktraceに関しての話はこのへんもあっておもしろい。っていうかStackTraceないんで、自分で実行した関数の名前を把握できない。うおお、、、

https://github.com/dotnet/corefx/issues/1420



System.IO.IOException: Too many open files

地味にすごく困るエラーがこれ。

や、Disqueのクライアントごときがこんなエラーだしてちゃいけないんだけどさ、

OSで指定してあるFileDescriptorの数を超えてTCPとかのコネクションを貼ろう、ってした場合に上記エラーが出る。

このパラメータをコード上からいじる、っていう文法がCoreCLR上にまだないんで、困っている。


例えばPythonとかだったら、

import resource


resource.setrlimit(

    resource.RLIMIT_CORE,

    (resource.RLIM_INFINITY, resource.RLIM_INFINITY))

みたいな書き方でOSに対してこのプロセスはどんだけのulimitを使うんだよって指定できるんだけど、この辺はCoreCLRだと

https://github.com/dotnet/coreclr/search?utf8=✓&q=ulimit

shellでセットしたりしてる以外は、、コードに特になってないような、、?

このへんはまあ困っていますね。はい。



Delegate.BeginInvoke/EndInvoke is DEAD

BeginInvokeとかEndInvokeは死にました。やったね?


Unsupportedエラー出そうぜ、っていう話が上がって、叶ってるっぽいんだけどちゃんと出ないことがある。再現したいな~~。

https://github.com/dotnet/coreclr/issues/3811


Socketの接続周りがドラマチックになった

Mac上とかでテストしたいな~みたいな時、IPEndPoint を使ってアドレスとかポートを指定しないとSocketをnewするのに失敗する。

どっかCoreCLRのリポジトリ上にもIssueがあった気がする。



Socketの切断周りがドラマチックになった

socket.CloseとかCloseAsyncとかが全部滅びた。

Dispose()使おうな。という感じで、これもどこかにIssueが上がってて全容が書いてあった気がする。

見つけたら書き足す。


実際にDisposeで書き直したところ、処理が軽量なのか問題は出なかった。なんか見逃してる気がしないでもない。



Reflectionにいろいろ足りない

いろいろやってる最中っぽい。

https://github.com/dotnet/corefx/issues/5381



あのメソッドは今

互換に関する情報は、下記が一番参考になる。公式の移植に関する互換性資料。

http://dotnet.github.io/port-to-core/Moq4_ApiPortabilityAnalysis.htm







wrote 2016/07/09 14:04:11

dornetconf2016jp行ってきた。


ツール周りについて

ツーリングプレビュー2 の状態なんで、今後も更新されていきそう。.json系のファイルは滅びてくれそうなんで期待している。



imports

importsでごまかして別形式(プロファイル)のdotnetStandard1.0未対応のライブラリでも使えるようにしてるっぽい。

プロファイルの形式による話なのか。


エラーメッセージのoutputってところのやつを書いてあげると、旧来の(dotnetStandard1.0未対応のライブラリでも)使える。

が、代替案であってろくなもんじゃない。できるだけdotnetStandard1.0対応のライブラリつかいたいね。


Disquuunもそのうちnugetにあげとくかな。



VSCodeからTerminal

メニュー > View

スクリーンショット 2016-07-09 17.01.04.png


便利~~~~



成果物をビルドする

dotnet publish



単体実行バイナリの生成

バイナリ生成は、project.jsonをいじって、runtimesを書き足して行う必要がある。



wrote 2016/07/09 13:10:33

1つのプロジェクト内でCoreCLRのビルドとUnityのビルドを共存させる


概要

あまり完璧ではない形だが実現できた。


やりたいことは、


・Unityでクライアントを書く

・CoreCLRでサーバとかを書く

・双方に跨る形で、データとかロジックのコードを共有する

・Unityのコンパイルに合わせてCoreCLR側もコンパイルする

・Unityの実行にあわせてサーバ起動する


とかそんな感じ。


Unityの使っている.Net 3.5っていう古代の生物と、CoreCLRだと、それなりに差異の数がある。



環境による差分

.Net 3.5のころに存在するいろんな機能が「よい実装方法や手法ではなかった」という理由でCoreCLR側でガンガン滅ぼされている。

詳しくはだいたいこっちに書いた。

CoreCLRで遭遇する楽しいエラーというか滅ぼされたものとかと戦う

http://sassembla.github.io/Public/2016:07:09%2014-04-11/2016:07:09%2014-04-11.html



で、今回実現できたフォルダ構成

こんな構成。Unityと外部とでコードを共有する仕掛けになっている。


UnityProjectFolder/

Assets/

いろいろクライアント専用コードを置くことができる。当たり前。


XrossPeer/

このへんに、クライアントとサーバで共有されているコードを置くことができる。

拡張子は自動的に~.client.cs になる。


XrossPeer_Peered/

このPeer=クライアントでだけ改変が必要なコードを置く場所。


XrossPeer_Util/

XrossPeerUtilility.cs

ログを吐いたりするための、全環境共通のロガー。

どのPeerでも使えるようになってないといけない、あんまり頑張らないロガー。


Editor/

この機構を動かすためのコードを置く場所。XrossPeerの提供者 = 自分が書いたコードしか置かれない前提の場所。

PeerがUnityのAssets以下にあるときにしか評価されないので、Unity以外のPeerへは出力されない。


主にコードの複製とサーバ側のコードのコンパイル、起動、再起動とかをハンドラの形で提供する。


ServerContext/

いろいろサーバPeerで動作するコードを置く場所。Assetsフォルダと同じ階層で、つまりUnityのコンパイルする対象外。


XrossPeer/

このへんに、クライアントとサーバで共有されているコード

拡張子は自動的に~.servercontext.cs とかになる。


XrossPeer_Peered/

このPeer=クライアントでだけ改変が必要なコード


XrossPeer_Util/

XrossPeerUtilility.cs

Assets/XrossPeer/XrossPeer_Utilフォルダ内と同じもの。




この機構のためにXrossPeerというAssetを開発して使っている。

Assets/XrossPeerフォルダにはクライアント側の共有コードが置かれ、XrossPeer_Peeredフォルダには「クライアントとサーバで異なるライブラリを使ったりする場合の差異のあるコード」を置く想定。

他に、全Peerで共通のUtilとしてログ機能とかを提供する。共通で出て欲しいログとかを書くとしたらこの辺になりそう。環境ごとのログ実装の差し替えも可能。




XrossPeer_Peeredについて

何を置くのを想定してるかというと、


具体的には、例えばJSONのエンコード/デコードについて、

・クライアントではUnityのJsonUtilityを使う

・サーバではJson.netを使う

などの場合に、共通のインターフェースを使うコードは各XrossPeer_Peeredフォルダ直下に置いておいて、

XrossPeer_Peered直下にはそれぞれのライブラリを使用するコード(型や引数などのインターフェースは共通で、実装のみを変えたもの)を用意する。

このXrossPeer_Peeredフォルダの内容は自動的にはコピーされないので、局所的なライブラリとか、

.Net3.5 ~ CoreCLR間で互換性のないメソッドとか記法を各Peered内に隠蔽することができる。

こいつを開発してる動機はまさにこのPeeredフォルダにあって、今後Unityのバージョンが上がろうが、動作するプラットフォームとしてのクライアント/サーバの差は絶対に出るし、

例えばJsonUtilityが良い例なんだけど、C++実装されてるアレらを超えるクライアント側ライブラリって中々無いわけで。


それを綺麗に分ける方法をずっと探していて、これを作った、という感じ。


コードのミラーリング機構あり

単に、クライアント -> サーバ、 サーバ -> クライアントへと、Peeredフォルダは除外した上でXrossPeerフォルダの中のコードを上書きする、という機構。


ただし、これだとどっちのコードをいじっているのかわからなくなるので、

差分検出機とコードの末尾に強制的に.client.csとか.server.csって付くように調整してある。


XrossPeer内に置いた全ての.csコードの拡張子は、そのPeerの属する名前に拡張子が改造される。

この機能はUnityのエディタ機能拡張として実装した。



Peerの抽象化

ここまで散々Peer = クライアント/サーバの二軸みたいに書いていたが、別に「UnityのAssets以下にあるものと、その他のもの」くらいの最大的な区別しかなく、

ざっくり言うと

UnityのAssetsの中にあるPeer A と、フォルダBに展開されているPeer B、フォルダCに展開されているPeer C、、 みたいな拡張も可能にしている。

まあ普通複数のPeerを同時に動かすことは無いと思うんだけど、例えばバーチャルクライアントみたいなものをでっち上げたい時に役に立つ。


上の例だとA, B, Cっていう合計3つのPeerがあるが、このうちAを実際にプレイするクライアント、Bを僚機、Cをサーバ、みたいに振り分けることも可能なようにしてある。



サーバの起動コントロール

自分が作っているものの都合上、次のフックポイントがあると便利だった。


・特定のPeerのコードのコンパイルを行う(コントロールできるのはUnity外のみ、ようはCoreCLR系。

・特定のPeerのコンパイルの成否をどっかに吐く(単に書き出すだけになると思うが

・特定のPeerのプロセスを起動

・特定のPeerのプロセスを再起動


このへんはAssetStoreに出して通った健全?な手法があるんで俺そういうのやっててよかったなあと思った。



依存してるもの

CoreCLR環境が整ってないと、CoreCLR側がコンパイルできない。

MacだろうとWinだろうと一瞬で環境が用意できる。だいたい3分もあればマジでできる。

参考:

「.NET Coreとツール類の今」

https://docs.com/bonprosoft/4626/net-core



モロにCoreCLRのexeに依存しちゃってるので、その辺を整理整頓する方法を考え中。

同梱するわけにはいかねえべえ、、、


コード

ここ。 そのうちアップされる。

XrossPeer

https://github.com/sassembla/XrossPeer



試験中の奴はRolePlayingChatっていうのに含まれている。

RolePlayingChat

https://github.com/sassembla/RolePlayingChat


wrote 2016/07/05 15:57:53

Unity用 WebSocket ClientのWebuSocketっての作った


概要

いろいろC#でのソケット周りの技術の知識増えたので、改修しつつ。

まだ過去のテストが動かないのがアレだが。


WebuSocket

https://github.com/sassembla/WebuSocket


モチベーションとか

・WebSocket Clientだけの独立した実装っていうのがなかった。みんなServerと抱き合わせ

・Thread、Taskとか使わないでも非同期通信を軽量に実装できるよねっていうのができそう

・約ゼロコピー行けないっすかねっていう目測ができた

・connection per instance ていうの作ったら取り回しが楽なのでは?という実験

ろくなWebSocket Clientがなかった


約ゼロコピーは「とりあえずユーザーランドに行くまで一回もコピーしないよ」っていうあたりを指してる。

msgpackとかで頑張ってるのとは次元の違う、単なる詭弁。


最終的に軽量に実装できたと思う。



特にUnityで使う際の注意

OnMessageハンドラとかは、Unityから見たら別スレッドで飛んでくるデータになる。

で、MainThreadでそのデータを使いたい場合、

・lockしてキューに入れる

・Updateとかでlockしてキューから取り出す

とかが必要。


もうちょっと変形させて、

・毎フレーム、もしメッセージが来ていたら特定のメソッドをメインスレッドで着火する

とかの場合、UniRxとか使って、特定のメソッドがメインスレッドで発火するように設定する必要がある。


wrote 2016/06/11 13:20:14

スマフォでの課金機構のレシート検証について

概要

まとめる。

追記

Unity 5.5でのIAP の話を追加



語彙

ticketIdについて:

購入に際して対応するIdをサーバ側で先行して配布する、そのId。

連番などでないユーザーIdに紐づいた推測されにくい値が推奨。


購入手順は、

・プレイヤーが購入するアイテムを選ぶ

・サーバに問い合わせてサーバでticketIdを生成

・購入処理開始(プレイヤーに購入しますかY/Nをプラットフォーム機構で表示)

・キャンセルだったら無視(できればticketIdが終わったことをサーバに通知)

・購入成功であれば、プラットフォームのtransactionIdを未完了にしたまま、サーバへとreceipt + ticketIdを送付

・サーバ側でレシート検証

・レシートそのほかの検証がOKであれば、クライアントに結果を送付

・クライアント側でプラットフォームのtransactionIdを完了にしてDone



iOSの検証について

・ticketId & ユーザー情報で、実際に購買が行われていたかどうかチェック

・receiptをAppleに問い合わせる。0以外のstatusがある場合はダメ

・bundle_idがこのAppのCFBundleIdentifierか

・product_idがticketのものと一致するか

・帰って来たレスポンスのtransactionIdで、過去このアプリで使われた全てのtransactionIdとの重複をチェック

(チーターは他のアプリのticketを送ってきたりするので、すでに誰かが処理済みのtransactionだったら蹴る、とか。)

-> OK



Androidの検証について

・ticketId & ユーザー情報で、実際に購買が行われていたかどうかチェック

・receiptを復号

Base64Decode -> 公開鍵暗号

・内部に含まれているDeveloperPayloadに、ticketIdが含まれているかどうかチェック(もしかしたら入ってないかもしれない?)

(チーターは他のアプリのticketを送ってきたりするので。)

-> OK



参考

「iOS/Androidアプリ内課金の不正なレシートによる有料会員登録を防ぐ」

http://inside.pixiv.net/entry/2014/12/09/111310

Unity5.5以降のIAPについて

「Unity IAP サーバ側で検証~みたいなのを実装してた」

http://sassembla.github.io/Public/2017:01:05%2017-46-38/2017:01:05%2017-46-38.html



補:InitiatePurchaseでのpayloadについて

全然情報がない。

http://qiita.com/kivatek/items/e93e9cf11eba3fba176c

データ形式見せてくれてるけどドキュメントと整合性取らねば。


Unity社の実装

https://bitbucket.org/Unity-Technologies/unity-iap-samples.git

使ってない。役立たずーーー!!! これじゃ実際に試すしかないじゃん。もーーー。



payloadはAndroidでのみ効果があるのかな?

試すしかなさそう。

-> Productのインスタンス保持してたらちゃんとtransactionIdが生えたりしたので、無事比較することができた。

これで同一性に関しては保持できた。よかった、、、、


で、payloadは、これたぶんAndroid側はデータに入るんだと思う。

で、check時に内部を見れば良さげ。


wrote 2016/06/03 18:10:20

bluetoothがキレまくる事案


概要

MacBook 2016 earlyで、

一定時間でBluetoothでのテザリングが切れる。

その後、テザリングを再開できない(=


予想される原因

ユーザー名をインストール後に強引に変えた。

次なんかあったら再インストールしよう。



1.DHCPリース更新

意味なかった。



2.PRAMクリア

再起動 -> P, R, opt, cmdを押したまま -> そのまま押しっぱなしで2度Macの起動音がすればOK

効果あったっぽい?



3.CMSリセット

https://www.imobie.jp/support/mac-os-x-probelms-and-solutions.htm#a15



あと診断

http://gori.me/mac/mac-tips/79025


wrote 2016/05/21 14:27:53

C#で動くDisqueクライアント Disquuun


概要

なんでC#? なんでDisque? とかはまあ気にしない方向で。


これ。

Disquuun

https://github.com/sassembla/Disquuun


まだ最低限の機能が動くだけの状態。テスト書き足すの楽しい。



モチベーション

非同期で良い感じに動くDisqueのクライアントがなかったんで書いた。


だいたいあるDisqueのクライアントはRedisのコードを流用してるだけで、自分がDisqueでやりたい事(非同期、ループ化)を満たせなかった。



特にやりたかったのは、「Disqueに溜まっているJobを低燃費で最速で取りに行く方法」とかそのへんで、

Thread持ち出してGETJOB + NOHANGオプションで頑張って取りに行くとかがよくある利用方法だったんだけど、


疑似コード

var thread = new thread(N frame per seconds)

thread.Start(GetJob_FromDisqueQueue_WithNoHang)


これだとThread持たないといけないんだよな。

しかも変な分解能を所有しちゃう。


で、

Disqueだと、GETJOBはNOHANGオプションつけなければ & Disque内に該当するQueue/Jobが存在しなければ、

そこでTCPのレスポンス待ちでブロックが発生する。(この辺はDisqueがそういうデザインになってる)

その後、誰かがDisqueの該当するQueueにJobを入れれば、ブロックしてたGETJOBはQueueからJobを引き出して帰っていく。



このパターンがDisqueになんかJobが足された時の最速のGETで、要はGETJOBを投げといて、誰かがADDJOB -> GETJOB帰還、みたいなのを

実現できると良い感じで。


それが書きやすいようなインターフェースを備えたDisqueのクライアントが欲しかった。



で、Loop

Disquuunでは、Sync、AsyncとLoopという3つの実行パターンを用意してる。

Syncはぶっちゃけ誰も使わないと思うんでDeprecateにする予定なんだけど、


AsyncとLoopは次のようは書き方ができる。


Async

disquuun.GetJob(data).Async(

(command, data) => {

// async data receive point.

}

);



Loop

disquuun.GetJob(data).Loop(

(command, data) => {

// async data receive point.

return true;

}

);


Loopだと、非同期で着火するハンドラがtrueを返す限り、同じリクエストをDisqueにむかって投げつける。

この場合だと、GetJob(data) が再度非同期でDisqueへと投げつけられる。


DisqueにGETJOBを投げつけるためだけに、Thread(interval)を持ち出したり、Asyncの中に再帰を書かなくて済むようになるというわけ。


やったぜ!



インストールとか使い方

readme見て。



発音

でぃすきゅぅぅぅん




wrote 2016/05/16 16:08:48

ゲーム/プラットフォーム作る時の要件まとめ


概要

いろんな要件 = なんちゃらbility があるよね~ってなったので軽くまとめておく。

めんどうくさい。


前提

プラットフォーム/

ゲーム x N

みたいなぶら下がりをするゲームとプラットフォームの要素と要件を適当に書いておく。

プラットフォームの主目的によって如何様にも変わる部分と、ゲームならこの機能はいるっしょみたいなよくある話を区別なく列挙しとく。

運用と密接にアレする。


ここから先がまあ、その、要素。



認証bility

どう個人を特定するか



ログインbility

自動ログイン(アプリケーションのインストールに基づくログイン)

能動的なログイン(メール、パスワードに基づくログインと、3rdパーティAuthによるログイン



プラットフォームでのIDbility

ゲーム内IDとプラットフォームIDをどう関連付けるか。



機種変更bility

ユーザーが端末を変更する際の動作、ポリシー。



課金bility

認証は必須。お金が動くので、ユーザーと課金内容の紐付けが必要。



退会bility

伝説の退会できないプラットフォームとかもあったな。



お問い合わせbility

手段用意しとこうな。





wrote 2016/05/16 14:56:34

Cinemachine使って遊んでみる


概要

AssetStore見てたらついにリリースされていた、Unity用のカメラを制御するっぽいAsset 


Cinemachine

https://www.assetstore.unity3d.com/jp/#!/content/60946

有償(5月中はearlybird的なセールで$79)。

さてどうやって使うんだこれ。っていうことで使いながらドキュメント読んでみた。すげえぞこれ。



略式紹介

カメラのコントロールをするAsset。

スクリーンのどのへんに被写体が写ってほしいかから逆算してカメラをコントロールすることができる。


すげえ。センスいい。



ドキュメント

オンラインにあるのが全てっぽい。


base-rigについて

http://www.cinemachineimagery.com/base-rig/



サクッと把握したかったので、特に Base-rigについて のみを以下に訳している。以下。[]の中のは自分のコメント。

流し読み + 使いながら訳してるんで、なんかミス見つけたら教えて。


Base Rig:

Cinemachineの基礎で、いろんなモジュール含んでる。

Cinemachineは統合されたカメラ制御のシステムなんだが、既存のカメラとも併用できる。

すでに大量のカメラがあるようなゲームでも、Cinemachineをカットシーン用のカメラとして問題なく導入できる。

ただ、Cinemachineを使ってゲーム全体のカメラを構成すると、プレイ->カットシーン->プレイに戻る、とかがシームレスに作れる。



Base Rigに含まれてるコンポーネント:

CinemachineVirtualCamera

カメラ。次のような機構を含んでいる。

Priority

優先度、一番高いカメラが使用される。Important指定をしたカメラはその限りではない?

Noise

パーリンノイズによる手ぶれ。シェイクとか振動とかもある。

Composer

動的に被写体追跡する機構。

Transposer

特定の物体にカメラをマウントするための機構。


AUTOGEN_CinemachineRuntime

動作時に生成される、Cinemachineのエンジン。次のような機構を含んでいる。

 Blend Settings

複数のカメラをブレンドする機構。たとえばCameraAとCameraBを4秒間で移り変わり、1秒でCameraAに戻る、みたいなのを作る時、便利。

特に複数のカメラ間でブレンド方法が指定されてない場合、デフォルトのブレンド方法を適応する。


Debug

現在アクティブなカメラや、ブレンド中のカメラの情報をみるのに便利。PreferencesからOnにできる。

Preferences

Unity > Preferences > Cinemachine で開ける。デバッグモードをOnにしたり、Composerのコンポーネントに色付けしたりターゲットアイコンのサイズをセットできる。



CinemachineVirtualCameraについて:

CinemachineVirtualCameraにはモジュールをセットすることができる。(UnityのComponentとして。) 

Noise、Composer、Transposer モジュールによって、手ぶれを追加したり、カメラのコンポーズを動的に行ったり、対象を追跡するようなことができる。

これらはめっちゃ強力で、相互に連携可能。最高のカメラコントロールのために頑張ってある。


Unityでは、activeなカメラが同時に一つしか存在できないんで、効果的なカメラブレンディングには無理があった。

Cinemachineはまさにそれを克服するために作られてる。

具体的に言うと、無限にvirtualなカメラをセットでき、それらをブレンドし、Unity内でのたった一つのカメラとして振る舞うことができる。全て自動的にね。



CinemachineVirtualCamera オブジェクトと、そこに含まれるCinemachineVirtualCameraコンポーネントについて:

(Unity上でのvirtualCameraの作り出し方は、Cinemachineインストール済みの状態でHierarchy上で右クリック > Cinemachine > Virtual Camera)


CinemachineVirtualCameraコンポーネント パラメータの詳細:


Auto Add To Priority Stack

チェック入れると、自動的にオンになり、ブレンドにも使用される。(カットも自動的にされる。) チェックがない場合は、コードから動的に動かす必要がある。

Priority

Targets:

GameObjectをTransposer target枠に放り込むと、このカメラはその対象にマウントされた感じで動くようになる。(詳しくはTransposerの項をみよう)


Offsets

それぞれのオフセット。


Field Of View Offset

基本的にここでは放置しとくといいパラメータ。Composerモジュール内でセットすると良い。Composerモジュールを使わない場合はここでセットする。


Dutch Offset

カメラの傾き、チルト。


Noise Amplitude Scalar

Noise Speed Scalar


Settings

[Cinemachineでは、モジュールごとに自由に名前をつけて設定ファイルを出力しているみたいだ。設定はそこに保存される。

virtualCameraごとに、その設定を使うことができる。あと、Play中にもパラメータを保存できるっていうのがあって、すごくイイ。]


Show Camera Guides

[Composer モジュールがセットされてるときだけ表示される。]カメラのブレンド用のガイドが表示される。詳しくはComposerモジュールの解説をみよう。



Noise Module

Noise モジュールは多層的なパーリンノイズを使った手ぶれ生成機構で、揺れはComposer モジュールの処理が終わった後に加算される。

カメラのポジションと回転の制御をする。好きなだけパラメータ追加できるっぽいぞ。

[確かに好きなだけ追加できた。オェエ]

スクリーンショット 2016-05-06 16.35.12.png


手ぶれ生成をリアルにやるのしんどいんだけど、うまくやるとなんか映像に説得力みたいなものが出る。

[この項の続きはそのうちちゃんと訳す。]



Composer Module

このモジュールの凄さみたいなのの例が一杯ある。このモジュールは、オブジェクトを動的に追跡する。

キャラクターのボーンを追跡したり、複数のカメラをブレンドしたりできる。

被写体がどんな動きをしてようと、対象をcompositional settingsに基づいてカメラに捉えることができる。

正確に追跡したり、カメラの追尾に減衰率(ようはディレイ)をもたせたりとかできる。

Composerモジュールは、被写体がどんなところにあろうと、現実世界で実際に撮影したかのように(イイ感じに追っかけて)3D空間を2Dスクリーンに落とし込む。


縦の追跡ディレイ、横の追跡ディレイとか、個別に、好きにコントロールできるぞ。


内側の四角形(soft regions)に被写体が入っているうちは、Composerモジュールによって微細な動きは無視される。

被写体が内側の四角形を出た場合、跳ね返るように被写体を追跡する。


さておき、[ここからDeserts of Kharakの苦労話なので中略 Homeworld: Deserts of Kharak]

Composer モジュールは次のようにはたらく。

まず、撮影する対象(GameObject)を、CinemachineVirtualCameraのインスペクタ上の Composer Camera Target にセットする。

UnityGameObjectならなんでもイイ。複数のキャラクターからできてる集団の中心とかでもいい。

カメラが追跡する対象になる。


次に、そのオブジェクトがスクリーンのどのへんに写っていてほしいかを設定する。

[インスペクター上から「カメラが被写体をスクリーン上のどのへんに写すか」パラメータをセットし、Gameビューでそのプレビューができる。]

赤い'Hard'フィールドは、被写体がこのゾーンに絶対に入らないという意味で設定できる。フレームの淵とかに被写体が出ないようにセットするのがよくあるパターン。

スクリーンショット 2016-05-06 17.24.37.png


青い'Soft'フィールドは、被写体がそこに入り込んだ場合はゆっくりと被写体を中心へと追いやるようにできている。

[中略、細かい挙動の話]


被写体が中心の透明な'the dead zone'フィールドに来ている場合、カメラは被写体の細かい動きを無視する。

アニメーションによるキャラクターの中心位置の移動とか、移動物理エンジンの微細な振動を無視したりとかするのに使うといいと思う。


被写体をスクリーン上の指定した位置へと押し出す力[原文だとHorizontal/Vertical Soft Dampening]は、長年の経験でこういうデザインになってるよ!

[ここからちょっと訳し中。カメラのブレンド=被写体をスクリーンのどこに置くかみたいなのの設定をいっぱい作ってそれらの遷移とかの話がここから先。]



Transposer Module

Transposer モジュールは、カメラ自体の位置を動的に変化させる。カメラの位置のみに関連している。

カメラの回転に関してはComposerモジュールで行い、移動に関してはTransposer モジュールに担当させるととてもいい感じになる。


[中略、画像があってComposer Camera Targetには被写体、Transposer Camera Targetにはカメラの乗り物としてのオブジェクトを定義するといいぞみたいな話]


Transposerでは、Transposer Camera Targetにセットしたオブジェクトからのローカル座標でのオフセットを軸ごとに指定することができる。

また、各軸に対してDampening[ここでのDampeningはTransposerにセットしたオブジェクトをどれだけ熱心に即座に追うか、というパラメータ]をセットできる。


Transposer モジュールにはとてもパワフルな複数のモードがある。


Local Space on Target Assignment:

Transposer Camera Targetにセットされたオブジェクトに合わせてカメラの位置を動かす。


Local Space Locked Up Vector:

Composerでz-rollをセットするとかしない限り、カメラの上方向を固定する。

[オフセットを設定してたりすると、オブジェクトの横回転に際してオフセットもオブジェクトを中心に回転したりする。

結果としてカメラが回ったみたいに感じるが、実際回っているのはカメラをセットしたオブジェクト、っていう。ややこしい。]


Local Space Locked To Target:

Transpose Camera Targetにセットされたオブジェクトのforwardの向き、位置にカメラをセットする。

[より具体的に言うと、オブジェクトが回転すればカメラも回転する。Transposer使ってて意図しない挙動してる場合、このへんが原因なことが多い気がする。]


World Space:

Transpose Camera Targetにセットされたオブジェクトの位置(というか実際にはそこからオフセット分移動した位置)にカメラをセットする。

 


まとめ

可能性は無限っすわ。[なんかカメラを車Aに乗っけて云々するだけで車Bがめっちゃ綺麗に撮影できるんですよみたいな例]

さ~やってみよう~みたいな話。



訳はここまで。



所感

Transposerだけを使って、自撮りカメラみたいなのをセットしてみたんだけど、次のような設定が瞬殺でできた。


・被写体オブジェクトから一定の位置に、そのオブジェクトを撮影するカメラをセットする

・カメラは固定ではなく、被写体の移動に伴い、若干遅れて被写体を追ったりする

・x-z平面上のオブジェクトの移動に伴うカメラ追従は比較的素早く、y軸上のカメラ追従速度はめっちゃゆっくり、、とかが個別にできた。楽かよ、、

・手ぶれ機能みたいなのを使ってほんのすこーしゆらゆらさせてみたところ、絵のクオリティが上がったので震えていた。ドキュメントにもそのへん熱烈に書いてあった。


カメラの動きに関しての具体的な例は、http://www.cinemachineimagery.com/examples/ にいっぱい載ってる。

スクリーン上でのConstraintのかけ方がうまい。絵面で思いついても実装まで考えると頭痛くなりそうなもんなんだが。この人たちは実現してる。えらい。

もう俺がMain Cameraを制御するコードを自分で書くことはないと思う。






wrote 2016/05/06 15:01:52

QUICについていろいろまとめ


概要

勉強になる部分はあるのか。

そもそもUDPで通信するのを積んでみたいよね~っていう感じで。


資料

https://docs.google.com/presentation/d/15e1bLKYeN56GL1oTJSF9OZiUsI-rcxisLo9dEyDkWQs/edit#slide=id.gc34025b9a_0_0



QUICって何

multiplexedな接続をUDP上に構築するプロトコル

encあり

低レイテンシ

XOR FECでパケロス対策


比較対象

TCP + TLSよりGood。


どのへんが?


・接続

0 ~ 1RTT


・Streaming-level and Connection-level flow contrrol

? そういうパラメータ内部に持って頑張ってますよってだけの話なのかな。


・FEC recovery

パケロス対応

Forward error correction 

http://d.hatena.ne.jp/ASnoKaze/20160301/1456761476



・Multipath

MultipatTCPと同じような、複数の接続を持って冗長化とかその辺かな、、

https://en.wikipedia.org/wiki/Multipath_TCP


https://www.vunity.com/quic-multipath/



どこからモチベーション感じるか

RTTが少ない、一つの接続内でのデータフローを最適化できそう(このへんはHTTP/2での知見)みたいなところか。

パーツを見てて知りたいな~と思うところとしては、

・どうやって順番保護してるんだろ

・Multipathどうやってるんだろ(複数接続の連携は何かあるのかな? っていうかこれがmultiplexedの内容か。

このへんか。



Chromiumのコード読むチャンスがちょっとあるんでやってみよう。

あと読むならこれ。

https://github.com/google/proto-quic

linux上で動かしてやってみるかな。




wrote 2016/04/21 18:02:01

Unityの領域なのかC#の領域なのか切り分け


概要

Unity上でC#を使ってスクリプト書くときとか、「あれ、これってUnity 特有なの?それともC#の言語の話なの?」ってなって、

最初勉強するときハマったというかどう調べれば良いのかわからなくなったんで、その区分けの話。



大雑把な区分け

  • メソッドがUnityなにやら namespaceに入ってる関数とかクラスは全てUnityマター。なので、検索の時とかに「Unity なにやら」で検索するといい。
  • コンパイルエラーから察する
  • 動作時エラーから察する
  • それ以外のヒントのない要素は99%くらいC#マター。なので、C# うんぬんで検索するといい。



このへんの切り分けで最初困ったこと

  • Instantiate, Prefab, Hierarchyの価値観がわからん
  • StartCoroutineとか、Coroutine って言ってるけどC#ってCoroutineあったっけ、、



C#とCoroutine

端的に言うとC#にCoroutineと呼ばれるものはない。

IEnumeratorというかIteratorと、yield構文があるので、C#ではGeneratorを簡単に記述することができる。


Generatorについてはこのへん。

http://geekswithblogs.net/BlackRabbitCoder/archive/2010/04/21/more-fun-with-c-iterators-and-generators.aspx

(生粋のC#erのひとはもっと良い記事を知ってそうなんで教えて)


メソッドブロックを持ち、呼び出すたびにyieldからyieldまでを継続して実行し、値を返すことができる。


Unityでは、特にIEnumeratorを返すメソッドをUnityEngine.StartCoroutine()メソッドに渡すことで、Unityの決めたタイミングでメソッドを実行する、というスタイルで

ここでは継続的なコンテキストを持つコードを毎フレーム実行する、というCoroutineを実装している。


wrote 2016/04/19 13:34:52

ネットワァークエンジンの比較


概要

ここに登場するための条件としては、

・ネットワークエンジン/サービスであること

・ゲームエンジンとのインテグレーション可能(クライアントSDKがあるとか、サーバSDKがあるとかそのへん

・俺の観測範囲にある

というあたり。



エンジンズ

Photon

PRCとそうじゃないのの2つがある。

データ形式はいじれない。

サーバ内でしか開けられない。

Windowsサーバでしか動かない。



Lamberyard

そもそもデータ形式に制限どころか仕様がない

なんでもOKでなんにもない。まさに荒野の自由。



Monobitのアレ

PhotonのRPCだけのやつ。

データ形式はいじれない。



Unityのアレ

PhotonのRPCじゃないほうのやつ。

データ形式はいじれない。

サーバ内でしか開けられない。



通信経路とかの話

Lamberyard以外は、Client-Server間のデータのやり取りの方法、あとデータ自体の形式ついて、独自の方式やフォーマットを内包している。

これが良いか悪いかはいろいろ思うところがあるんだが、データ形式について開放しているケースはない。

DataDesignerみたいなツールが作れるといいのかな~と思わんでもない。


想定されているUsageと会社の色

Limitationやデータデザイン、データ経路の詳細をみていくと、各会社のカラーが見えて面白い。(と俺は勝手に解釈している。


広範なUsageに対して答えを出すわけにはいかない、というUnity社のような事情や、

いろんな方式をカバーして、情弱、情強おかまいなく使用者の量を最大化しようと考えていそうなPhoton、

Photonのパクリやすそうなところを特に考えなしにパクったような感じのMonobitとか、

何も用意しないことで失うものがないLamberyardなどなど、


いろんな会社のいろんな戦略があるんだなあというところ。





wrote 2016/04/17 14:59:51

今つくってるやつ x 2


概要

いろいろ作って遊んでいる。



その1.ShaderKitchen


逆引きシェーダー辞典。

Unityに限らないけど、シェーダーのコードの意味やどんな見た目になるのかを一覧 + 深追いできるサイト。の、プロトタイプ。


モチベ

・見た目からシェーダーの基礎まで深追いしたい

・シェーダーの勉強するサイト一箇所にしたい



-> 実装

・シェーダーを見た目で「あ、これいいな」から選んで、

・そのシェーダーのコードを、マウスオーバーとかクリックで深追い = 意味とか効果の勉強ができて

・用意されてるサンプルと同じUnityPackageのDLができるんで、手元でも同じ見た目のものが動かせる。

・リアルタイムにコードを変えて云々はしない。ただしクリックしたコードが描画のどこに影響するかはドローバッファのアニメーションで見せる



プロトタイプのURL

☆限界サイズの試験中で20MくらいなのでPCで見てね!ギガ死するよ!!  (あとupされてるのがdropboxなんで重量的に死にやすいかも)


https://dl.dropboxusercontent.com/u/36583594/outsource/UnidonWeb/index.html


プロジェクトのURL

https://github.com/sassembla/ShaderKitchen


みため

スクリーンショット 2016-04-10 15.55.09.png

スクリーンショット 2016-04-10 15.53.55.png


・(実装中)Unityで作ってるので、赤い線を左右に自分で動かしつつ、シェーダーの効果を見比べることができる。

half.png



ほか


・すべてUnity製

Unityのプロジェクトを自動的に分解してWebサイトっぽいデータ構成(index + AssetBundle x Scene)にするツールを作った。

Unidon

https://github.com/sassembla/Unidon


その2 Automatine(オートマタイン)


タイムラインでキャラクタの動作を設定するツール 。


Sequencerとは違った概念で、タイムライン上に状態とかコードを置いて実行できるようにするやつ。



モチベ

Automatineは、タイムライン上に状態やスクリプトを配置し実行できるユーティリティ。特に次のようなことを簡単に管理するのを目指している。



こんな見た目

スクリーンショット 2016-04-10 16.22.21.png



どんなことを楽にするのか

「数フレーム後に~する」みたいな時間指定での動作をGUIから作れる。


例えば次のような動作「ダッシュ斬り」を考えてみよう。


ボタンを押す -> 3frame後にキャラが一番近い敵に向かってダッシュ開始

-> 敵めがけてダッシュ(可変フレーム)

-> 十分近くに行ったのでダッシュ解除、惰性のブレーキモーションを10frame

-> 攻撃モーション

-> アニメーションにあわせた待ちフレーム後にダメージ処理

-> 惰性の5frame

-> 最初いた場所を向いて、ダッシュ20frame

-> 元いた位置にたどり着いたら、向きを変えて待機モーションにして、行動終了


みたいな「N frame後に~して、その次は、、」「もしこうなってたら、その次は、、」がいっぱいあるコードを、GUIからセットできる。

手で書かなくてよくなる。


Automatineを使うと、上記のようなコードのタイミング指定や長さ、やること、状態の調整とかがGUIで完結する。



Sequencerとの違い

Unity5.4以降でSeqencer(Timeline tool)が入るが、それとは異なる用途を目指している。

☆このへんのSequencerのモチベーションの話は、Unite2016で自分が質問&確認した時点での話なので、確定ではなく変わっていくかもしれない。


ざっくり書くとこんな感じ。

やりたいこと

Sequencer

Automatine

Assetをタイムラインにセット

✔︎

-

シーン単位でタイムライン実行

✔︎

✔︎

キャラ単位でタイムライン実行

difficult

✔︎

一部の動作を繰り返して実行

-

✔︎

状態の保持、管理

do yourself

✔︎

状態遷移の定義、実行

-

✔︎

スクリプトの実行

✔︎

✔︎

1つのスクリプトを継続実行

do yourself

✔︎

AIの実装

not aimed,

do yourself

✔︎


Sequencerがシネマティックなシーケンスを制御するのを主なMotivationにしているのに対し、

Automatineはより細かい粒度での「キャラクターやオブジェクトの状態を管理し、スクリプトの実行と継続動作」を実現することを主な目的としている。


ようはコンテキストサイズの違いで、Sequencerは「Sneneとか、被写体の群とか、でかいシネマティックなコンテキスト」をコントロール対象にしていて、

Automatineはもっと小さな粒度の、「インスタンス単位の小さなコンテキスト」をコントロールの対象にしている。

わかりやすく書くと、下記のような差がある。

Sequencerのコントロール対象: オーケストラ指揮者 + ぶら下がってる指揮下の演奏家 x Nの協調動作

Automatineのコントロール対象: 演奏家の単独動作


特徴

すでに実装されている大きな特徴として次のようなものがある。



実行時のGUIとコード例

たとえばで、格ゲーのキックみたいなのを作ろうとすると、こんな感じの見た目で、

・4f目から移動開始、19f目まで移動


・22f目から25f目まで攻撃判定(Damageの列)


・0fから39fまでずっとダメージ受ける可能性があり(Damagedの列)

・22fから31fまではカウンターヒットを受ける可能性があり


・26fから36fまででキックの戻りアクション


みたいな複雑なことの表現がこのGUIだけでできる。


スクリーンショット 2016-04-10 16.50.30.png


で、実際にゲーム側で使う時のコードは以下のような感じ。



定義

using UnityEngine;

using Automatine;


public class Attacker : MonoBehaviour {

Auto<string, bool> auto;



実行

int frame = 0;

void Start () {

auto = new Kick<string, bool>(frame, "start~!!");

}

void Update () {

auto.Update(frame, true);

frame++;

}



こんな感じのコードを書くと、動く。

で、実行しているautoについて、状態を取得することができる。



状態を取得

void Update () {

if (auto.ShouldFalldown(frame)) {

Debug.LogError("Kickが終わったので何かに切り替える:" + frame);

}

if (auto.Contains(AutoConditions.Damage.Lv1)) {

Debug.LogError("自分が攻撃を出してる瞬間、この時相手は、、?っていうのが書けるブロック:" + frame);

}

if (auto.Contains(AutoConditions.Damaged.CounterHit)) {

Debug.LogError("カウンターヒットになる状態:" + frame);

}

if (auto.Contains(AutoConditions.Damaged.Normal)) {

Debug.LogError("通常やられになる状態:" + frame);

}

auto.Update(frame, true);

frame++;


みたいな感じで書ける。



おまけで、

・frameを+しないと動かない

・frameの+が1より多いと、その回数ちゃんと回る = 早送り可能

・定義時にセットしてる型は自分で勝手に決めていいやつで、GUIにアタッチしたコードに渡る


という。

実行時のログはこんな感じ

通常やられになる状態:0

通常やられになる状態:1

通常やられになる状態:2

通常やられになる状態:3

通常やられになる状態:4

通常やられになる状態:5

通常やられになる状態:6

通常やられになる状態:7

通常やられになる状態:8

通常やられになる状態:9

通常やられになる状態:10

通常やられになる状態:11

通常やられになる状態:12

通常やられになる状態:13

通常やられになる状態:14

通常やられになる状態:15

通常やられになる状態:16

通常やられになる状態:17

通常やられになる状態:18

通常やられになる状態:19

通常やられになる状態:20

通常やられになる状態:21

通常やられになる状態:22

自分が攻撃を出してる瞬間、この時相手は、、?っていうのが書けるブロック:23

カウンターヒットになる状態:23

自分が攻撃を出してる瞬間、この時相手は、、?っていうのが書けるブロック:24

カウンターヒットになる状態:24

自分が攻撃を出してる瞬間、この時相手は、、?っていうのが書けるブロック:25

カウンターヒットになる状態:25

自分が攻撃を出してる瞬間、この時相手は、、?っていうのが書けるブロック:26

カウンターヒットになる状態:26

カウンターヒットになる状態:27

カウンターヒットになる状態:28

カウンターヒットになる状態:29

カウンターヒットになる状態:30

カウンターヒットになる状態:31

カウンターヒットになる状態:32

通常やられになる状態:33

通常やられになる状態:34

通常やられになる状態:35

通常やられになる状態:36

通常やられになる状態:37

通常やられになる状態:38

通常やられになる状態:39

Kickが終わったので何かに切り替える:40

通常やられになる状態:40

Kickが終わったので何かに切り替える:41

Kickが終わったので何かに切り替える:42

Kickが終わったので何かに切り替える:43

...



最後に、コード(IEnumeratorメソッド)を各フレームにセットすることができる。

このへんは近いうちに追記する。


wrote 2016/04/10 15:52:36

Unite2016に行ってきたぽ


概要

今年は平和に過ごす。

Unite 2016

http://japan.unity3d.com/unite/unite2016/schedule



モバイル端末向けのUnityアプリケーションの最適化実践テクニック


profiling-with-instruments

http://blogs.unity3d.com/2016/02/01/profiling-with-instruments/



Reading the PlayerLoop

Updateとか


PlayerRender

OnWillRender


UI::CanvasManager;;WillRenderCanvases 

Enlightenのメソッドもあるっぽい。



StartCoroutine使った場合、実行ブロックが2箇所に分割される

初回以降の後半はDelayedCallManager内で呼ばれる。

負荷をみるときに気をつけようねみたいな。



MemoryProfiler

見やすそう。MemoryProfiler

https://bitbucket.org/Unity-Technologies/memoryprofiler


DL -> Window -> Open MemoryProfiler Window -> start なんちゃら



メモリ、ヒープについて

GCは断続的に走ってる。

GC Alloc カラムで観れる。


anonymous methods & closuresを避ける

毎回初期化しなければいいのではっていう。


データパーシングについて

基本、textのパースに関わるものはすげー遅い。

3つの方針

1.don't parse text

bake text to bin ScriptableObject


ゲームデザインの値とか。


2.働きを小さく

チャンクに分ける

必要なとこだけパース


3.別スレッド

Pure C# types only.

Resourcesフォルダの中身は、起動時にインデックスを作っている

これは非同期にもできないし回避もできない。遅い。


Resources -> AssetBundle にすると、特にクソ遅い端末()とかでもスタートアップ時の恩恵があるっぽい。



Runtime

Propertyにセットするような値を毎フレームつくるのはやめよう。

static int とかでキャッシュ扱いにしておくと高速かつ軽量。


RegExp, StartsWith, EndsWith とかは漏れなく重い。特にReg。


::Box

String_

とかのキーワードでプロファイラで探すと見つけやすい。



Unityグラフィックス最新機能ガイド


Multithreaded Rendering

DowbleWide Rendering

2割くらい高速化できてる印象



Cinematic Image Effect

SSR

ScreenSpaceReflection



Progressive Light Mapper

GI



Unity CollaborateとUnity Cloud Buildを使って開発サイクルを高速化!

GUI上のボタンから一発でCloudに上がる。

メンバーはinviteで増やせる。


gitとかの置き換えというよりは、デザイナーさんとか、非エンジニアの人でも容易に同時編集作業ができるようなものを目指している印象。

質疑応答でもそういうはなしがめっちゃ多かった(gitとかとの互換性は?とか)


現状での作ってる人たちの理想形というかモチベーションは、

Collaborate = 「バージョン管理的な機構とは別軸」「ゲームジャムとかでの使用を念頭に置く」「別途バージョン管理をすることを念頭においていそう」という感じ。


ハードウェア性能を引き出して60fpsを実現するプログラミング・テクニック


ゲームロジックを別スレッドで実行

Vitaだと4コアあるんで、1コアを使おうみたいな。

MainThreadからデータを受け取るところとかが必要 ダブルバッファ自作

MainThreadからしか使えないAPIは!? 使わない!! なるほど!!

ダブルバッファ自作

ゲーム処理とrender処理のUpdateに分ける。


GPU

vartices直書きできる?らしい。5.4から公開されてるぽい



動的なメモリ確保をしない

struct使いまくる


パフォーマンスメータの話

vブランクの開始と終了に近い関数のコールバックを探す

PSVitaの場合、OnPreCull、OnPreCullで計測。


RenderThread, GPUは計測困難だった

今後に期待


GCのトリガになるのは?

Monoの場合は事前にAllocされてるメモリがnewでいっぱいになったら。


極限すぎるやつ

https://github.com/unity3d-jp/AnotherThread



Unity上級者を目指すなら知っておくべきデバッグテクニック集


ここでは

バグ = 思い通りに動かないこと


x 例外が出たらバグ、例外がでなければ仕様



どんどん問題の切り分けを行う

外部接続の確認 -> パラメータ -> プログラムの流れを確認する -> OSを差し替えてみる

問題を絞り込むまではログ、問題が絞り込めてからはデバッガ



映像制作のゲームチェンジャー:メイキング オブ ”THE GIFT”


いろいろてっく。Tweetひろってあとで拡充する。




ビルディング・2Dワールド in Unity ~2D機能のあれやこれや~


Tiled

タイルをならべるの、一個一個並べてると人生が終わる

タイル選択 ->  インスペクタからDraw Mode -> Tiled にして、タイル自体の横幅を変更すると、サイズに対してテクスチャで埋めてくれるようになる。


2分が2秒に。



オブジェクト内の軸のありようを変えられるようになってるぽい。

たとえば見下ろしし視点のゲーム作りたいときとかに使うといいのでは。



オリジナルタイル作成

アトラスを複数のタイルのコレクションから構築できるみたいな話かな。


アーティストもプログラマもウェルカム!新タイムラインエディタのご紹介


Sequencer

シーケンサ、アセットベースでいろいろセットしたり動かすことができるタイムラインツール。

Directorと呼ばれるAPIで操作。

ゲーム時間とかそのへんの、どの時間軸を使うのかは選べそう。

.playable拡張子でファイルとして保存される感じ。

コードからだと、Sequenceクラスのインスタンスという形で読み出したものをDirectorにセットして使う。



Cinemachine

カメラの画角とかを設定、ここで設定した内容をSequencer上にセットして、カメラの移動とかブレンディングみたいなのができるような感じ。

詳細はよくわからんかったがカメラのパンとかに関してもGUIベースで指定できそうで、ぐう有能そう。


サイトみつけた。これは、、めっちゃくちゃ期待できそうなカメラコントローラ、、!!

http://www.cinemachineimagery.com



スクラビングでスクリプトのプレビューができるのか

毎回ゼロ地点から計算すればあるいは。



APIからタイムラインを構築することは可能か

今はできないけどニーズによっては。 



AssetBundle化

まだできない。今後?



個別に質問

・コンポーザブル?入れ子にできるか?

今後できる。ただし、見づらいから推奨はしない。


・事前定義必須?

必須。アイデンティファイはAssetIdとか、Hierarchyにものが載せてある前提な気がする。


・AIみたいに使うのは想定している?

特には想定してない。スクリプトくっつけることはできるから頑張れ。


・動的に参加するものを追加できるか?あるグループにキャラを追加、みたいな

想定してない。事前に足しておこうな!

・今はframe単位でロジック動かすのをやってるけど、「この方向に向かうのをこの時間内ずっと行う」みたいなのを考えたい。とのこと。

Coroutineみたいなアイデアだな~と聞きながら思っていた。自作ツールに近そう。



見えてきたSequencerのモチベーション(作ってる側が目指してるもの)

・イベントを発効できるAfterEffects

・シーン単位とかでの使用をメインに据えてそう

・ムービー、導入モーション、特定のカメラワークとかがメインな用途な気がする。



マルチシーン編集の使い方

Hierarchy上から右クリックメニューで、個別のシーン保存したりできるようになってた。



GetRootGameObjects

GetRootGameObjectsメソッドで、特定のシーンのHierarchyのルートになっている(=Hierに列挙されている)GameObjectを取得することができる。



gameObject.scene.buildIndex

gameObject.scene.buildIndex で、そのGameObjectがどのシーン由来なのか把握することができる。


便利~~



Unityとアセットツールで学ぶ「絵づくり」の基礎(ライト、シェーダー、イメージエフェクト)


絵作りの基礎について。Look Devの話。

どのくらいのリアル感を、出てくるものすべてに対して揃えるか

その法則を作りたい。


質感 = 色、陰影、タッチ


マテリアル、ライト、カメラ

マテリアル

マップ、シェーダ


ライト

直接光、関節光、ホワイトバランス、ソフトネス


カメラ

HDR、フォーカス、スクリーンスペースでのイメージエフェクト


ライティングにおけるモチベーション

どんなストーリーを持たせるのか(状況、何が起こるかの予告になっている感じ


作為的な感じで、特に対象を明るくするとか。


スライドをもとにコーネルボックスやってみよう。

カラーブリーディング

影に壁の色とかが入り込むこと


色はライト依存

diffuseがどんな色だろうと、ライトで全部変わる。


光の加法混色



各ライトの減衰特性

DirectionalLight

減衰しない。


PointLight

リニアに減衰する


AreaLight

急激(距離に対して逆二乗)で減衰する



GIの設定

Lighting Windowでやる。

GIまわりのところがメインで、他はサブっぽい。

エミッシブを使って云々するとライトみたいな感じになるが、実際にはライトではなくエフェクトっぽい。


BakeGIのほうがモバイルに向いてる感じ。昼夜を~みたいなのは、Precompiledなやつを使うことになりそう。


シェーダ

PBRValidateっていうツールがある。


イメージエフェクト

Scriptになってる。

資料の順番にいろいろ足すといい感じ。



Unityのロードマップと来場者の皆様によるオープンディスカッション


R&Dとか、今まさに作ってそうなもののはなし。あとメインの質問コーナー


(俺)WebSocketとかをサポートする予定はありますか

ない。



(俺)WebViewって各プラットフォームに公式機能としてどうですかね

ない。



C#の7とかそのいつ対応されそうなの?みたいな話

現在のコンパイラのバグ、プロファイラ、とかをみていって、まず6に対応すると思う。その後はその後。



Webプラグイン死んだんだけど、今後ってWebGL一本なの?どの程度いけんの?

割と動くようなフェーズ。


2つ新たにサポ

simd

sharedMemBuff


おまけ

公演直前に流れてるMade with Unityな作品群の中に、初めて見るやつとかまだリリース情報出てないやつとかが結構あった気がしてる。

かっこよかったのもいっぱいあったので、どんなのがあったのか、ちまちま集めてみようかと。

https://docs.google.com/spreadsheets/d/1I8UqjLLrtq_MvlfJLiY_z0-4M7KcXygjgAB60e5W6e4/edit#gid=0

よかったら情報ちょうだいです。

wrote 2016/04/04 13/57/28

docker/ubuntuにnginx-luajit入れる


概要

ソースコードから入れてビルドとかそのへん。

参考になるのはこれ。

lua-nginx-module

https://github.com/openresty/lua-nginx-module



まずubuntu自体をdocker machine内に用意

docker run --name="nginx-luajit-websocket-pubsuber" -it ubuntu:14.04 /bin/bash



一応、環境を最新のものにする

apt-get -y update

apt-get -y upgrade



/usr/src/に移動

cd /usr/src/



curlいれて

apt-get install curl



nginxのソース入れて

curl -O http://nginx.org/download/nginx-1.9.12.tar.gz



lua-nginx-moduleのソースを入れて

mkdir lua-nginx-module

cd lua-nginx-module

curl -L -O https://github.com/openresty/lua-nginx-module/archive/v0.10.2.tar.gz

cd ../



nginx-devel-kitをDL

mkdir nginx-devel-kit

cd nginx-devel-kit

curl -L -O https://github.com/simpl/ngx_devel_kit/archive/v0.2.19.tar.gz

cd ../



luajit入れる

DL元はここ。

http://luajit.org/download.html


curl -L -O http://luajit.org/download/LuaJIT-2.1.0-beta2.tar.gz



いろいろ解凍

tar -xvzf nginx-1.9.12.tar.gz とか。落としたやつ全部その場に解凍。



Luajitをビルド

lualitをビルドするためにいろいろ入れる。

apt-get install make

apt-get install gcc


次のようなbuild.shを、LuaJIT-2.1.0-beta2フォルダ内に作成する。


build.sh

luajit_projectpath=$(pwd)

make

make install "PREFIX=$luajit_projectpath"



nginxをビルド

nginxが依存しているpcreとzlibをインストール

apt-get install libpcre3 libpcre3-dev

apt-get install zlib1g-dev


次のような内容のbuild.shを、usr/src/フォルダ直下に作成(行儀がわるい。


build.sh

PROJECT_PATH=$(pwd) #/usr/src


NGINX_VERSION=1.9.11


# luajit 2.1 is already built.

LUAJIT_FOLDER="LuaJIT-2.1.0-beta2"

cd $LUAJIT_FOLDER

sh build.sh

cd ../


# luajit required from Lua-nginx module. set export.

export LUAJIT_LIB=$PROJECT_PATH/$LUAJIT_FOLDER/lib

export LUAJIT_INC=$PROJECT_PATH/$LUAJIT_FOLDER/include/luajit-2.1


# same folder contains below.

NGX_DEVEL_KIT="/usr/src/nginx-devel-kit/ngx_devel_kit-0.2.19"

LUA_NGX_MOD="/usr/src/lua-nginx-module/lua-nginx-module-0.10.2"


cd nginx-1.9.12


# make & install nginx to PROJECT_PATH/NGINX_VERSION

./configure \

        --prefix=$PROJECT_PATH/$NGINX_VERSION \

        --with-ld-opt="-Wl,-rpath,$LUAJIT_LIB" \

        --add-module=$NGX_DEVEL_KIT \

        --add-module=$LUA_NGX_MOD


make -j2

make install

で、ビルドする。


cd /usr/src

sh build.sh

うまくいけばできるはず。



luaコード

WebSocketとかのコードを入れる。

docker-machine scp なんたら


luaコードはこちら

https://dl.dropboxusercontent.com/u/36583594/outsource/lua.zip


1.9.x/以下に置いて、luaフォルダとして解凍するだけ。



nginxのコンフィグ設定

1.9.x/conf/nginx.confを、luajitを使えるような形にいじる。

こんな感じ。

#user  nobody;

worker_processes  auto;


error_log  logs/error.log;

#error_log  logs/error.log  notice;

#error_log  logs/error.log  info;


#pid        logs/nginx.pid;



events {

    worker_connections  1024;

}



http {

    include       mime.types;

    default_type  application/octet-stream;


    #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '

    #                  '$status $body_bytes_sent "$http_referer" '

    #                  '"$http_user_agent" "$http_x_forwarded_for"';


    #access_log  logs/access.log  main;


    sendfile        on;

    #tcp_nopush     on;


    #keepalive_timeout  0;

    #keepalive_timeout  65;


    #gzip  on;

    # lua_code_cache off;


    # set search paths for pure Lua external libraries (';;' is the default path):

    lua_package_path ";;$prefix/lua/lib/?.lua;";


    # set search paths for Lua external libraries written in C (can also use ';;'):

    # lua_package_cpath ';;$prefix/lua/shared/?.so;';


    server {

        listen       80;

        server_name  localhost;

        #charset koi8-r;


        #access_log  logs/host.access.log  main;


        location / {

            root   html;

            index  index.html index.htm;

        }


        # disque client route.

        location /disque_client {

                content_by_lua_file lua/disque_client.lua;

        }

    }

}

太字のところが特にnginx-luaの動作に必要な設定。

この状態で起動することができる。


起動した状態で、nginxの待ってるIPの80番ポート/disque_client にアクセスすると、WebSocket接続後、nginx-luaを経由してdisqueへと接続される。



別コンテナにdisque入れる

Disqueはここから仕入れてる。

https://github.com/antirez/disque/releases


curl -O -L https://github.com/antirez/disque/archive/1.0-rc1.tar.gz

tar -xvzf 1.0-rc1.tar.gz

apt-get install make

cd disque-1.0-rc1/

make



Disqueの起動

src/disque-serverを叩くと、デフォルト設定で起動する。

portは7711が使われている。

/usr/src/disque-1.0-rc1/src/disque-server




wrote 2016/03/27 16:20:41

rust環境 on VSCode & Atom


概要

AutoComplete、Buildとか含めていろんなツールを見てみる的な。

Rustに関してはずっとVSCode使ってたんだけど、VSCodeよりAtomのほうが圧倒的にいい環境だった。



VSCode編

後述するAtom編のほうが、できることが多いしエラーも見やすいのでオススメ。


RustyCode

VSCode上でいろいろな機能を組み合わせるやつ。

racerなどに依存がある。


RustyCode

https://github.com/saviorisdead/RustyCode


基本的にはこいつのInstallationに付き合えばOK。



racer入れる

RustyCodeがAutoCompleteに使っている。

racer

https://github.com/phildawes/racer


cargo install racer

RustyCodeのセッティングファイルにパスを指定(後述)



Rustのコード

racerがGoToDefineとかでRustのコード自体も要求してくるので、入れる。

固定でさえあれば、適当な場所でいいんだと思う。

Rust

https://github.com/rust-lang/rust


rustfmt入れる

rustfmt

https://github.com/rust-lang-nursery/rustfmt


cargo install rustfmt


RustyCodeのセッティングファイルにパスを指定(後述)



RustyCodeのセッティングにいろいろインストールしたものを指定

フルパス指定しないとダメだった。

{

    "rust.racerPath": "/Users/tomggg/.cargo/bin/racer", // Specifies path to Racer binary if it's not in PATH

    "rust.rustLangSrcPath": "/Users/tomggg/.cargo/rust-master/src", // Specifies path to /src directory of local copy of Rust sources

    "rust.rustfmtPath": "/Users/tomggg/.cargo/bin/rustfmt", // Specifies path to Rustfmt binary if it's not in PATH

    "rust.cargoPath": "/usr/local/Cellar/rust/1.7.0/bin/cargo", // Specifies path to Cargo binary if it's not in PATH

    "rust.formatOnSave": false, // Turn on/off autoformatting file on save (EXPERIMENTAL)

    "rust.checkOnSave": false, // Turn on/off `cargo check` project on save (EXPERIMENTAL)

    "rust.checkWithClippy": false // Turn on/off `cargo clippy` project on save (EXPERIMENTAL) (cargo-clippy should be installed)

}



Atom編


ここみればOK

http://qiita.com/nacika_ins/items/044c87fd8bd1d7c41191

コマンドライン上からいろいろインポートするだけ + Atom上のセッティングに2行書いたら終わる。

racerとRustのコードも必要なんで、一応書く。


racer入れる

AtomでもAutoCompleteに使っている。

racer

https://github.com/phildawes/racer


cargo install racer

Atomのセッティングにパスを指定

/Users/SOMEONE/.cargo/bin



Rustのコード

同じく、racerがGoToDefineとかでRustのコード自体も要求してくるので、入れる。

固定でさえあれば、適当な場所でいいんだと思う。

Rust

https://github.com/rust-lang/rust



あとはAtomのセッティングいじって再起動する。

wrote 2016/03/26 18:26:02

iPhoneの通信をWiresharkでみる方法


概要

Wireshark便利っすね、、、

1.iPhoneとかをMacにつなぎ、デバイスIDをなんとかして見る。

単にUSBとかで繋ぎ、XcodeとかiTunesで見れればOK。

見たいデバイスIDは、38桁の子文字と数字の文字列。



2.コマンド打ってイメージとしてMac-iPhone間を接続する

rvictlコマンドを打ってMacとiPhoneを接続。


rvictl -S 0123456789012345678901234567



3.wiresharkを起動して、調査対象にrviを選択する

こんだけ。楽っすね~~

wrote 2016/03/22 22:41:26

UnityMokuMoku 行った


概要

これ。

【プチLT】Unityの新機能で遊ぶ会【もくもく】

https://unity-bu.doorkeeper.jp/events/40412


AssetGraphとShaderKitchenをいじって、その辺の話をしていた。



AssetGraph

UnityのAssetBundleをGUIでなんとかするやつ。

いろいろあっていろいろある感じで、とりあえずパブリックベータみたいな感じ。


AssetGraph

https://github.com/unity3d-jp/AssetGraph


今回のもくもくでは、こいつをメンテしていた。



ShaderKitchen

シェーダーのコードの勉強と、実際に動くunityPackageをDLできるWebサイト。ここで開発中。

ShaderKitchen

https://github.com/sassembla/ShaderKitchen



LTで言い忘れたこと

Unity5.3から、AssetBundle作成時にオプションが増えていた。


BuildAssetBundleOptions.ChunkBasedCompression

このオプションをオンにした状態でAssetBundleを作成すると、圧縮、展開時の性能がテラシュールウェアで紹介されていたような感じになる。

【Unity】5.3以降AssetBundleの各種圧縮形式のパフォーマンス比較

http://tsubakit1.hateblo.jp/entry/2016/03/19/022019



wrote 2016/03/20 17:02:26

Docker Toolboxを使う


概要

DLして云々

https://www.docker.com/products/docker-toolbox


Docker QuickStart Terminal起動するとデフォルトのDockerMachineが動作する用のVMが一つ作られる。

名前はdefault。



Docker Machine自体をリストアップ

ホストにインストールされてるDocker Machineをリストアップ

docker-machine ls



Docker Machine VMを起動する

ホストのマシンからコマンドで起動できる。

docker-machine start default



起動したDocker Machineにログイン

docker-machine ssh default



Docker Machineを再起動する

docker-machine restart default



Docker Machineにhello-world imageをインストール、実行する

docker run hello-world


docker-hubからDLしてきて実行してる感。


コンテナ名をつけてimageを実行する

docker run --name=“something” hello-world

で、たとえばimageが永続的な代物だと、Docker HubからDL -> 起動したままコントロールが帰ってこなくなる、とかがある。

-dオプションでロックを回避できる。


動作については、別のTerminalとかからログインしてpsとかで見てみるとわかり易い。



過去に起動したimage一覧を見る

docker ps -a



Docker Machineから特定のイメージを削除する

docker rmi hello-world



Docker Machineにインストール済みのイメージ一覧を出す

docker-machineの動作vmを起動した状態で、

docker images


例えばhello-worldを入れた後なら、

docker@default:~$ docker images

REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE

hello-world         latest              690ed74de00f        5 months ago        960 B



特定のコンテナを実行する

docker start -a something



特定のコンテナを停止させる

docker stop something



特定のコンテナを削除する

docker rm something

一度消すと、ps -aからも起動記録が削除される。



Docker Hubからイメージの検索を行う

docker search SOMETHING



ポートフォワーディング

-pオプションでfrom:toが書ける。

コンテナ実行時にセットする感じ。

docker run -p fromPort:toPort something



試しにnginxを起動してアクセスしてみる

起動とバインド

docker run -d -p 8080:80 nginx


アクセスするためのホストからのipは、ホスト側からDocker Machineの情報を得ることでわかる。

docker-machine env


tomggg:~ tomggg$ docker-machine env

export DOCKER_TLS_VERIFY="1"

export DOCKER_HOST="tcp://192.168.99.100:2376"

export DOCKER_CERT_PATH="/Users/tomggg/.docker/machine/machines/default"

export DOCKER_MACHINE_NAME="default"

# Run this command to configure your shell: 

# eval $(docker-machine env)


って感じなので、ブラウザから次のurlをhttpでロードしようとすると、

http://192.168.99.100:8080


スクリーンショット 2016-03-13 17.15.37.png


やったぜ。



ホスト上のパスにコンテナからアクセス

例えばnginxとか入れて、そのコンテンツをホスト側に用意したい場合、

runの-v オプションで実現ができる。


docker run -v targetPath:destinationPath



runのオプション一覧

-d バックグラウンド実行

-v ホストパスの割り当て

-i 標準入力の解放

-t コンテナに仮想コンソールを接続

(-it) 標準入力コンソールを接続した状態になる

-p portの割り当て



知りたいこと

attach


imageへのscp



wrote 2016/03/13 15:34:04

WebuSocket + nginx_luajit_WebSocket + Disque(RC)の限界値


概要

時間単位でのメッセージ打ち込み量と負荷をメモまでに。

テストが存在するリポジトリはこれ。

https://github.com/sassembla/WebuSocket

ConnectionServerはMac内にたててある。



環境

MacBook Mid2015

CoreM 8GBなのでしょぼい。


クライアント: Unity Player

サーバ: Unity Editor

Unity 5.3.3p1



Disque、どんな時にCPU負荷が上がるか

serverから10,000 message / frame 以上の入力を受けた時。

messageは20byte程度。


どうも入力自体は一瞬で済むらしく、DisqueのCPU負荷が跳ね上がる。

WebSocket自体はちゃんとデータを送付できてるらしい。


100,000 message/ frame には耐えた。その際のDisqueの最大CPU使用率は65%ほど。

一瞬で9%くらいまで負荷が下がるのすげーな。



登り1,000 message/frame、下り10,000 message/frame 同時、できた

1クライアントに対してのupとdownを同時に行う試み。Disqueはこのへんに割と余裕で耐えた。


Disque 26%、 nginx 23% 。


サーバ側は同期的にメッセージぶち込んでいるんで、これを定期 + 別スレッドに変えてみよう。

より現実に即している。


ってわけでいろいろテストを書いてやってみた。


突破できた事象


1.サーバから1frameで10,000通のメッセージを投げてクライアントへと脱落なく届ける

Test_4_0_ReceiveManyTimes(),



2.サーバから1frameで100,000通のメッセージを投げてクライアントへと脱落なく届ける

new Test_4_1_ReceiveManyManyTimes(),



3.クライアントから1frameで1,000通のメッセージを投げてサーバ->クライアントへと脱落なく届ける

new Test_4_2_SendManyTimes(),



4.クライアントから1frameで10,000通のメッセージを投げてサーバ->クライアントへと脱落なく届ける

new Test_4_3_SendManyManyTimes(),



5.サーバから1frameで10,000通のメッセージを投げてクライアントへと脱落なく届ける

+ クライアントから1frameで1,000通のメッセージを投げてサーバへと脱落なく届ける

new Test_4_4_SendAndReceiveManyTimes(),



6.サーバから1frameで100,000通のメッセージを投げてクライアントへと脱落なく届ける

+ クライアントから1frameで10,000通のメッセージを投げてサーバへと脱落なく届ける

new Test_4_5_SendAndReceiveManyManyTimes(),



7.サーバから非同期で10,000通のメッセージを投げてクライアントへと脱落なく届ける

+ クライアントから非同期で10,000通のメッセージを投げてサーバへと脱落なく届ける

new Test_4_6_SendAndReceiveAsyncManyTimes(),



この間一切の切断、取りこぼし、メッセージの変質などが存在しない。



うーんいいね~~。あとは重たい箇所のあぶり出しとか最適化を必要になったらやろう。

時間を計るとかするかな、、フレーム数とかだと安定しそう。

wrote 2016/03/12 0:54:15

JACKまわりパァ~っと見てて思うところ


概要

このへんについて、FUDにならないように気をつけて書く。

なんか間違ってそうだったら @toru_inoue まで一報ください、、土下座して直す。


資料

JACKの解説

https://source.android.com/source/jack.html


JACKを使ってjava8の機能を使う話

http://developer.android.com/preview/j8-jack.html#configuration


JACKの解説記事(ちょこちょこ表現が違うんでなんかちょっと内容が古い気がする

http://tools.android.com/tech-docs/jackandjill


用語

Javaの由来が大きく2つに分かれそうなんで、JVMで動く前提のjavacでコンパイルするjavaをJVM java

JACKでコンパイルするjavaをJACK javaと勝手に呼ぼうと思う。


実現され、標準になりそうなもの


1 .Something.java -> dex変換

.java -> .class -> いろいろ -> .dex


だったのが、


.java -> JACK -> .dex になる。


.classを挟まなくなるので、今まで存在していたみたいな

「別の言語コンパイルして混ぜて、最終的に.classを吐く」

みたいなのをAndroidでのアプリ開発に使用することができなくなる。


例えばscalacとかだと、.javaと.scalaファイルを読んで、.class吐いてたけど、

これってもう動かせないのでは?っていう。

でも大丈夫、.jarとか.classからjackへと突っこめるツールチェインがあるんで、なんとかなる!



2 .jar -> jill -> .jack or .dex変換

おおまかにこう。


.jar(or .class) -> JILL -> JACK -> .jack or .dex


.jackはJACKでコンパイルしたものを.dexではなくライブラリとして吐き出す場合の拡張子。


なーんかページによって言ってることが妙な気がするが、自分が参考にしたのはこれ。

https://source.android.com/source/jack.html


.classからはJILLを介してJayce(独自中間表現)が吐けて、それをJACKでimport、.jackを吐くことができそう。



ざっと見た感じこんな感じなので

.classをビルドに関与させるにはJILLを介さないとダメ、かつライブラリ扱いになりそうなんだけど(確実に.class作成後じゃないと噛み合わせられないんじゃないかと思うわけだが)


それでいいのかな。という感じ。


例えば.scalaとかをJACKで書いた.javaと共存させたい場合、

ツールチェーンでJACKを通るルートでは.javaが書けるけど、そこから呼び出せるScalaのコードとかは、

.javaを編集してる瞬間にはすでにコンパイル済みの状態で.classになってないといけないのでは??っていう。


具体的なコンパイルフローはこんなの。


1. Scalaのコード書く(このコードはScalaとJVM javaで書ける)(ただしこの領域で完結している必要がある。理由は後述)

2. .classにしてJILLに食わせて.jackにしておく

3. .javaのコードから.jackライブラリで定義されてるScala由来のコードを呼ぶ、とか


これ以外のルートがなさそうな気が。



上のルートだけだと困りそうな理由

上の1で書く言語は、そのコンパイル単位で依存関係が閉じていないといけないはず。じゃないと.classにできない。

なので、1で書いてるコードから、3で書くJACK javaのpublic classの参照とかはできないのでは?っていう。(逆は当然できるはず。)


これはまあ、「.classとか.jarをライブラリにする」っていう作業なんで、用途としては合ってる。

で、これを律儀に守る限り、Kotlinで自由に書きたい! アプリケーションのメイン部分をKotlinで!!、みたいな書き方はできなそうで。

JACKでコンパイルする.javaのほうに、ライブラリに対してハンドラを全力で渡す、みたいなブートストラップを書くのかな?


それ、、えっと、、、メインをJACK java以外で書きたい人の精神は耐えられるのかな?? 


あっでもライブラリがJACK java以外で便利に書ける+それを合一できるのはすごくいいな。



楽観も悲観もしてないようなこと

Androidの公式サポートしてる言語はJavaとかGoなので、それ以外の言語を使うのに関してはもう抵抗がある。

昔ScalaでAndroid App書いてたけど、やはりとても辛かった。


で、JACK javaでとりあえずJava継続って感じなので、いいんじゃねーかなーという。



個人的な感想

まだなんかビッグニュースがあるそうなんで、

1.新言語発表!! モダンなツールチェーン(まさかここがJACK、、、みたいなのは大いにありそう)で.dexを吐ける! .jackも読める!!

2.JACKは.javaをサポートする最後の独自コンパイラ世代として全てのJava資産の回収とかリライトをサポートする


みたいな流れだと胸熱だなあと思っている。

.class -> .dexは本当にろくでもないツールチェーンだと思ってるんでなくなってよかった。


書いてて思ったけどJACKのJはJavaのJだからJACKで別言語コンパイル -> dexはなさそうだな。

公式の新言語出るといいな。



wrote 2016/03/10 23:50:37

XrossPeerっていう複数Peerでコンテキストを共有する仕組みを作っている感じ


概要

ざっくり言うとClientとServerで同じコードが動くやつ。ユニットとして独立性を持つ。

特定の言語に限定したものではなく、基礎として継続が実現できる単位とかを持ってる言語ならどれでもいけると思う。


デザイン大変だった~~



機能一覧

・コードの差分検出、duplicate

・ログ

・判断と実行の分離(判断だけしたい、実行だけしたい、みたいなのの分離)



気が向いたら書く。




wrote 2016/03/03 20:27:47

AWS Lumberyardについてメモ


概要

AWS、ゲームエンジン乗っけられるサービス始めたってよ

動かすのとかチュートリアルは割愛。



サービス区分

まずLumberyardというゲームエンジンがある。

次に、GameLiftという「LumberyardをAWS上で動かす基盤サービス」みたいなのがある。



Lumberyard

中身はCryEngine。

forkしたもので、オリジナルに対して投資はしているが買収とかではない。

Client(PC、Consumer、SmartPhone、VRとかで動く)

スマフォとVRは今後サポート。


ゲームエディタ + ゲームエンジンのオーソドックスな構成。いってみりゃ普通。

ただ、AWSとの連携を抽象化してるレイヤーがあって、強烈な部分も。



強烈な部分

Lumberyard上のノードエディタにAWS LambdaとかAWS DynamoDBとかがポンと置ける。

サービス登録とかは別途、って感じなんだろうけど(試してない)、ゲーム中に動作するノードの部分として、


1.ここにきたらDynamo上のデータをこのキーで取得

2.もし値があったらこっちのルート

3.なかったらこっちのルート


とかをノードエディタで書けるのはすごい。超強い。そして怖い。

かる~~いGUI操作の結末として大量にリクエスト流れそうなんですがそれは。

まあ慣れの問題だろきっと。


GameLift

Lumberyardを「サーバ上で特にいろいろやって」動かすための基盤サービス。

このサービスを使わないでもLumberyardをAWS上で動かすことは可能。


ざっくり次の機能と、それに対する課金体制を持つ。

・オートスケーリング

・アクティブ状態のゲームのスワップ

・ユーザーのIdentify

・ユーザーの接続、切断のAPI

・ゲームのステートの生成、破棄などのAPI(ちょっと理解が違うかもしれん)

・以上


はい、強いですね。


オートスケーリング

まーインスタンス足したり引いたり。AWSの真骨頂。

急な負荷でも大丈夫、ガンガンと、、、ガンガンと、、、



アクティブ状態のゲームのスワップ

サーバへのデプロイ時にversion値を付加し、「動作しているゲームを別versionのものに切り替えていく」といったことができるっぽい。

まーアップデートとかデグレードとかをAPI化しましたみたいな話。


ユーザーがActiveなversionへとじわじわ遷移していくのかな。試してないけど。

まあダウンタイムはないよねって話。



ユーザーのIdentify

GameLiftは上記の機能を持つにあたって、ユーザーのIdentifyを勝手にやってくれるっぽい。

もっとも「DAU1000あたりいくら」っていう課金条件があるんで、そのためのものだと思うけど。

次に書く「ユーザーの接続、切断のAPI」とかの基礎としてIdenfityがある印象。



ユーザーの接続、切断のAPI

これらのAPIが定義、提供されている。

発生時にイベントハンドラがなんか言う。


で、ところで、これらのAPI、特に接続がミソで、このタイミングでDAUベースでちょいちょい金がでていく。



ゲームのステートの生成、破棄などのAPI(ちょっと理解が違うかもしれん)

ユーザーの寿命の他に、ゲームのステートみたいなものの寿命も管理できる。

推奨されてるゲームの形状は、「マッチして短期間で解散するもの」みたいな感じで、永遠に稼働し続けるMMOみたいなものは想定していない。 このへんはドキュメントにもしつこく書いてあった。



以上


そう、以上なんだ。


接続、切断とかのAPIはある。


、、、

、、

えっじゃあClient-Server間のゲーム中のデータをやり取りするAPIとかはどうなってるの? っていう疑問を持った?

持つよね?? その疑問持つの俺だけじゃないよね?

無い。全くの自由なんだ。


Client(PC上で動くLumberyard) <-> Server(AWS上で動くLumberyard) 


この2つのPeerのあいだの情報転送は、

接続、切断、ゲームのstate生成とか変更のAPI以外、

何にもない。



君はどんなプロトコルを使っても(多分)いい。


例えばServer側のLumberyardで全部計算して結果を動画でブロードキャスト(Do you remember SHINRA?? )してもいいし、

Client、Server双方で同様のゲームロジックを回して整合性はServer準拠、とかをやってもいい。


どんなプロトコルでもいいわけだよ。

その、、、Client側とServer側が受け入れられて、AWSに乗っけることができれば。


StartとEndだけは定義されてメソッドもハンドラも用意されているんで、、、


Cross Peerでのシンクロナイズとか、そういうのもまあ、、やろうと思えば、、できるわけだ、、、

自分で作れば、、、



Lumberyardのソースコードに関する制約

無い。

すべてオープンソース。


なので、たとえばPhotonみたいな、

「パケットの形状はこのフォーマットです」

「開けるのはServerに到達してからです」

「開いてからしか判断できません」


みたいな制約は無い。素敵だ。Unityですらこの辺は制約として持ちそうなんでアレだが。


っていうか通信部分は基礎以外本当に何も無いもんね!!!


しかも改変するのも自由(ただし再配布は禁じる。そりゃな。)



おおざっぱなLumberyardに関する制約

オンプレミスで動かしても良い。無料。

AWSで動かしても良い。これも無料。GameLiftなどの構造を利用する分にはDAU単位の課金がつく。


ほかのクラウド事業者やレンタルサーバ上で動かすのは禁止。

純粋な制約はこの一項のみ。



twitch

Lumberyardと連携。

チャットの内容をGameにフィードバックできる仕組みがありえる。

チャットからのコマンド入力みたいなもの、応援とかエフェクトとか。

ゲームに対するSlackの発展形か。

 


課金方法の提供

T-シャツ Amazonを介して販売 小売から配送まで

「A選手の優勝の瞬間スクリーンショッT-シャツ」とかができるわけですねすごい。

企業からしたら、商品開発の門戸が増える感じっぽい

App課金とかは従来通り。



ローカルで動かすテストキットがほしいです

一発で他人プレイヤーのログイン代替とか、テスト用のサーバ(micro)とか。

考えてみるかも。



今後?

ほかのゲームエンジン??が乗ると嬉しいな??みたいな話はあると思った。



チュートリアル

YourFirstGame っていうシリーズがあるのでやってみようぜみたいな。



感想

LumberyardはAWSに連携できる機能を内包したゲームエンジン。

GameLiftはそれを使ってGBaaS的な機能を持たせたフレームワーク。


Game Backend as a Service ? それともPlatformか?



とりあえず知ることができてよかった。

wrote 2016/03/03 19:06:42

初学者のときその分野について知りたいことをまとめてみた


概要

ちょうど客観的に悩んでいるのがわかる生き物がいたので観測がてら。

具体的な意味はない。言葉を列挙しておくだけ。



これは普通なのかどうか

何かにチャレンジしてて、予想外に高難度(自分が勝手知ったるものとことなるセオリーとか仕組み)を見た時、

まず恐怖するよなって思う。


何故怖いかというと、「実はミスリーディングをしていて見当違いの方向に進んでいて、進んだ挙句できないのでは?」みたいな疑問がでてくるから。


そんなとき知りたいのは、「これが普通なのかどうか」。

おまじない否定主義者なんで、自分は「仕組みがあって動いている、君のアプローチに対してその手法はよくある試みなのでそのままでいい。初めは面食らうだろうが参考になる情報はこういう感じ」とか言いたい。



区分

概念の名前とか、用語が列挙されてる場所とかがあるといいな~と思う。

完全網羅までいかないまでも「その群がどんな概念で仕分けられる代物なのか」とかが理解できると、自分が正しいことをしようとしてるのか、勘違いの挙句に本当に無理なことをしようとしてるかを理解するチャンスになる。


完璧さはいらないけど大まかな思考のための区分、みたいなのが聞いておけると便利。


特に思いつかない。


wrote 2016/02/28 21:44:40

Unityでの定義済み関数とかの呼ばれ方についてメモ


概要

なんか自分の理解をメモっておいたほうがいいような気がした。

あくまで自分が「調べたうえでこんなだった気がする」っていうメモになってしまう。例外はいっぱいありそう。


複数のScriptのUpdateとかどういう順で呼ばれるの

http://answers.unity3d.com/questions/46107/in-what-order-are-all-the-update-functions-called.html


load順。つまりInstantiateした順とか。



Updateとかってどうやって呼ばれてるの

MonoBehaviourを継承してるクラスから、特定の名称のメソッドの実装を検出してぶっ叩いている。


なのでprivateとかで書いても呼ばれる。Buffers - 67.png



http://gamedev.stackexchange.com/questions/115573/how-are-methods-like-awake-start-and-update-called-in-unity


これの最後の回答者と同じ理解。ポイントついてねーけど。

InstantiateあたりはUnityのC++のレイヤを呼んでた気がする。


どっかに「空でもUpdateを定義すると時間をロスする」みたいな記事があった気がする。

わかる人いたら@toru_inoueまで連絡くれると嬉しい。加筆とか訂正したい。



スマフォとかのAPIを読んでる部分

externとかで名前や引数の定義つきポインタを共有、ぶっ叩かれたらポインタに情報がいくのでそれで動いているという理解。

Buffers - 65.png



Kinectとかハードウェアが提供してるもの

スマフォとかのAPI呼ぶのと同様、特定の名称の関数をぶっ叩くポインタ保持レイヤが中間にあると思っている。

なのでこの辺は内部でインスタンス化だけ済ませてC#の関数を呼んでいるのが多い気がする。


まー関数が呼ばれるだけのほうが都合がいいんで、何がいつ呼ばれるかはドキュメント読もう以外にないのが難点。

C#での構造を持っていない、呼ばれるメソッドが存在するだけのケースが多くて、一般的な補完機構にもでてこないしな。

Buffers - 66.png



wrote 2016/02/28 18:53:17

すしのしおり 2016 Early


概要

禅、ガルパン4DX、温泉



予約状況

禅、予約できないので開店前に並ぶ。

ガルパン確保した。

温泉、いけば入れる。タオルとかも貸してくれる。


オールグリーン。



集合

JR新宿駅 ロマンスカー乗り場 西口地上改札口 9時15分集合

チケットは自分がまとめて買う。

map_3d.gif



移動手段

はこね11号(MSE10) 

発 09:30  新宿

着 10:38  小田原



目的地

駅でタクシー拾って「禅、寿司、よろしくお願いします。」とか言えば大丈夫。



スケジュール

11:00 食べ始める

~13:30 移動開始

14:00 劇場到着

14:20 上映開始

あとはその場の流れで(湯に)当たって帰る







wrote 2016/02/26 13:02:35

Unity5.3.2, 5.3.3系でAssetBundleがiCloudに入っちゃう暫定対策[fixed]


概要

5.3.2系のみならず5.3.3系p1でもまだダメ。これだけかどうかはわかんねーけどまとめる。

ただ、検証方法がAppleの作ったGUIごしのものなのでリアルタイム性がすこし怪しく、鵜呑みにせず信じるために疑ってかかってほしい。

→ 5.3.4p1以降で解決された。


症状

iOS用にAssetBundleビルドしてWWW.LoadCacheOrDownload で取得するとなんとデータがiCloudに載る

具体的には、こうなる。

IMG_0816.PNG


親にむかってなんだそのデータは!!!

取得したAssetBundleが見事にiCloudに載っとる。これは死ぬぞ。



何がまずいのか

何がまずいって、これ万が一AppStoreの申請を通過してしまうと、AssetBundleや自前で用意したリソース保持用のフォルダが

ユーザーのiCloudに載ってしまう可能性がある。


AppStoreで審査があるおかげで蹴られて気づいた(人から自分はさらに聞いて調べた)んだが、

万が一すり抜けると、数ギガ単位のリソースをユーザーのiCloudにアップしてしまう。

iCloudにはユーザーのデータが従量課金ベースで載っているのがデフォなので、ミスると評判的にも痛い。っていうか死ねるのでは。



原因と解決法

AssetBundleをDLしたあと、iOSのアプリケーションキャッシュ内に保存する際のフラグ設定をおこなう内部APIがあったんだけど、

その設定値がAssetBundle DL時 のみおかしかった。


該当の処理では、Xcodeでの実機用ビルド時に定義されている以下のファイルの関数を使っている。


Filesystem.mm

extern "C" int UnityUpdateNoBackupFlag(const char* path, int setFlag)

{

int result;

if(setFlag)

{

u_int8_t b = 1;

result = ::setxattr(path, "com.apple.MobileBackup", &b, 1, 0, 0);

}

else

{

result = ::removexattr(path, "com.apple.MobileBackup", 0);

}

return result == 0 ? 1 : 0;

}


で、この関数、AssetBundleの保存以外にもいろいろな所からつかっているみたいなんだけど、

AssetBundleを保存するタイミングのやつだけ、setFlag = 0 (Excludeしない)という感じで来てた。


Unity Japanに問い合わせたところめっちゃ早く返答がもらえて、「現状使用している方法が古いので、最新でこんなのどう?」っていうコードサンプルをもらった。

で、


最終的に、関数を次のように書き換えると救われる。

とりあえずUnityでゲームつくっててiCloudの世話になることは無いので(暴言)

固定値でexclude = YESを叩きつける。


extern "C" int UnityUpdateNoBackupFlag(const char* path, int setFlag)

{

    NSLog(@"path:%s, setFlag:%d", path, setFlag);

    int FIXED_YES_NUM = 1;

    return [[NSURL fileURLWithPath:[NSString stringWithUTF8String:path]] setResourceValue:[NSNumber numberWithBool:FIXED_YES_NUM] forKey:NSURLIsExcludedFromBackupKey error: nil] != NO;

}



一応貼っておくと実行時のログは次のような感じ。

2016-02-19 17:11:39.513 ProductName[595:201891] path:/var/mobile/Containers/Data/Application/7D89FD21-A2D1-42B6-AE4C-F5559366E4B9/Library/UnityCache/Temp/f34e32a1dd7804da1921ba641bbdffb9, setFlag:1


2016-02-19 17:11:39.521 ProductName[595:201773] path:/var/mobile/Containers/Data/Application/7D89FD21-A2D1-42B6-AE4C-F5559366E4B9/Library/UnityCache/Temp/f34e32a1dd7804da1921ba641bbdffb9/__info, setFlag:1


2016-02-19 17:11:39.522 ProductName[595:201773] path:/var/mobile/Containers/Data/Application/7D89FD21-A2D1-42B6-AE4C-F5559366E4B9/Library/UnityCache/Shared/e540cdd1328b2b21e29a95405c301b9313b7c346, setFlag:0


2016-02-19 17:11:39.522 ProductName[595:201773] path:/var/mobile/Containers/Data/Application/7D89FD21-A2D1-42B6-AE4C-F5559366E4B9/Library/UnityCache/Temp/f34e32a1dd7804da1921ba641bbdffb9/__data, setFlag:1


2016-02-19 17:11:39.526 ProductName[595:201865] path:/var/mobile/Containers/Data/Application/7D89FD21-A2D1-42B6-AE4C-F5559366E4B9/Library/UnityCache/Shared/e540cdd1328b2b21e29a95405c301b9313b7c346/__info, setFlag:1


setFlag = 0で来てるのが、AssetBundleの保存。

どっかで値が逆転してるか初期値がおかしいか初期値が入ってないか、な気がする。

Unityへは報告ずみ。



結果

Victory~~~~!!

IMG_0817.PNG



追記

自分でも確認したい人向けに下記を用意した。


再現サンプルリポジトリ

https://github.com/sassembla/ShaderKitchen/tree/assetbundle_debug_sorasu



プロジェクトを、ツールバーの Unidon > Publish Site からビルドできる。


ビルド時に、Assetsフォルダと同じ階層に、UnidonWeb/AssetBundle というフォルダ+アセットバンドルが作成されるようになっている。

実機で動かす際は適当なCDNとかにそれらをアップ、DLするURLを書き換えてみてほしい。


アプリケーション実行時、実行時に自動的に1つのAssetBundleを取得しキャッシュしている。

キャッシュにはWWW.LoacFromCacheOrDownload を使っている。

現在までUnity5.3.2系で確認した結果おかしい感じなので、ほかのバージョンでも動かしたりしてみてほしい。

誰か。



さらに追記

ちなみにAssetBundleだけなのか? っていうとさにあらず、

確証がないが、「LoadFromCacheOrDownload」内で使っている関数を、他のAPIが使用している可能性は調べていない。

つまり


「自前でAssetBundle保存箇所作ったから平気だぜ~」

とか


「そもAssetBundleつかってないから平気~~」

とかは


ありえないかもしれない。


少なくとも自分は自分に影響する範囲のチェックしかしてないので、

レッツ調査。


なんかわかったら教えて。Twitterとかで。



さらにさらに追記

5.3.2p4が来てたんで試してみたけどやっぱまだ増えるわ。次かな、、


さらにさらにさらに追記

強火ですすめの人が5.3.2f1でも起きてることを突き止めてくれました。詰んでます。

http://d.hatena.ne.jp/nakamura001/20160220


ランタイムの問題なんで、つらいな。



さ4追記

5.3.3f1でもダメ

これのパッチかな。


た5追記

エクスカリバー255本に増やそうな。

5.3.3p1でもまだダメ。

changeset見てから「あ、、でももしかして、、、もしかしたら、、」みたいなのがあって触ってたけど無駄っぽいので追うのをやめます。

アイドルを卒業します!



5.3.4p1のfixedに入ってた

やったね! ~完~


wrote 2016/02/19 17:17:27

CoreCLR -> IL2CPP、、の前に、EditorでCoreCLR


概要

UnityのEditor側でCoreCLR動かすと良さげ。


具体的にはLinuxとかMac上でC#のサーバをそのまま動かせそう。

ちょっと前に作った「UnityEditorをゲームサーバにして開発する」みたいなのが

とても良い感じにできるようになる。


ので、Unity上からCoreCLRのコントロールができるツールキットを作る。


モチベーション

これができると、まずはUnityEditorでC#5系が使える。

そいつはそのままWindowsServer(絶滅危惧種)で動かせるし、もちろんLinux上でも動かせる。

絶賛RC段階だが。



つづく。

wrote 2016/02/19 1:52:37

Unidonのデモページ


概要

これ。

Unidon

https://github.com/sassembla/Unidon



WebGLのむっちゃ重いビルドに付き合わずに動かせる範囲がこれだけあればわりとマシ。



unidonDemo.gif



あとはURLジャンプのしくみと、こないだの記事の修正をしなければ。

wrote 2016/02/18 1:01:32

週刊Automatineマガジン 5. jsonとかデータからAutoを作る


概要

Automatineでは、GUIからいろいろ調整したTimelineとかをコードの形で出力することができる。


でもこれだと、変更を加えるたびにいちいちコンパイルしないといけない、、オラそんなのいやだ、、、


というわけで、AutomatineをGUIで弄る -> jsonデータを吐く -> jsonデータを実行時に読み込む -> 実行 ということができる。

すでにリリースしちゃったゲームの調整すらできるというわけさ。



データ出力手順

GUIの一番右上の「Export As Data」ボタンを押す。

スクリーンショット 2016-02-15 22.20.45.png


すると、すべてのAutoのデータがjsonとして

Assets/Automatine/Runtime/Generated/Json フォルダに出力される。

スクリーンショット 2016-02-15 22.23.36.png

拡張子は.jsonになっているため、Assetsフォルダの下だけれど、Unityの影響は受けない。

これらをサーバなどに置いて、動的にDLしてAutoとして使用することができる。



使用方法

次のようなAutoを使うコードがあったら、

Auto<int, int> auto = new Atk_Punch<int, int>(frame, 100);


次のように書き換えることができる。


var atk_punchJson = //通信結果やファイル読み出しなどで得たAtk_Punch.jsonの中身

var atk_punchData = AutomatineJsonConverter.JsonToAutoData(atk_punchJson);

Auto<int, int> auto = Auto<int, int>.RuntimeAutoGenerator(atk_punchData)(frame, 100);

これで、Atk_Punch.jsonに入っているAutoの情報を、特定の内容のAutoとして初期化することができる。


初期化コストは無視できるくらい小さい。

(クラスとして持っている場合と負荷を比較したら、もちろんjsonからの変形のほうが負荷が大きいとは思うけれど。)



制約

この機能によって、jsonを介して、動的にAutoを生成することができる。 いちいちコンパイルし直さないでも、どこかから最新のAutoの情報を取得して~っていうのが、実機でできたりする。

素敵。



ただし制約がある。

なんのことはない、「すでに動いているゲームに対して、動的にコードを追加することはできない」ことに起因する制約がある。


1.ConditionType, ConditionValueを動的に増やすことはできない

2.Coroutineを動的に増やすことはできない

3.Changerを動的に増やすことはできない


Autoの中にあるTackを移動したり、TackにセットしてあるConditionやCoroutineを切り替えたり、タイミングや長さ、Timelineの数などを変更することは自由自在にできる。


ただし、使用される対象であるCoroutineやChanger、ConditionType、ConditionValueについては、これらはデータではなくコードなので、動的に追加することはできない。

これらはコンパイル時に「あらかじめ」いれておこうね、っていう話になる。



まーーーUnityそれ自体の制約でもあるし、iOSとかのプラットフォームの制約でもあるし。






wrote 2016/02/15 22:18:11

Unity製のブログ製造機みたいなもの


概要

今はやりのサーバレスWebをUnityで!!!


Unityで動くWebサイトジェネレータつくってみた。

これ。

Unidon

https://github.com/sassembla/Unidon


作った物体のサンプル(4.4MB + more)

https://dl.dropboxusercontent.com/u/36583594/outsource/UnidonWeb/index.html


現状のUnityでWebサイトを作る実用的な機構を目指したりしていた。

これ自体が欲しかったというより、この機構を拡張したものを作ってて、

要件切り出したら見事にCMSっぽい物体だったんでまとめた。習作みたいな。



ワンタッチで魅惑のビルド時間

こういうボタンがあるんで押してみるといいよ。

スクリーンショット 2016-02-13 17.11.15.png



Motivation

・UnityのEditorから、単にPublishボタン押すとブログみたいなもの作れる、ってなったらいいよな

・できるだけLaunchページ軽くしたいよな

・できるだけUnityをそのままWebにしたいよな

・AssetBundleにするの勝手にできるといいよな

・ビルドの高速化したいよな


このあたりを成立させることができる構成を考えていた。だいたい叶ったと思う。

まだ欲が足りないが。



基礎設計

基礎部分、インデックスを担当するシーン、それ以外の記事の元になるシーン x Nという分割をする。


基礎部分はビューを持たず、インデックスとか他のシーンはすべて勝手にAssetBundleにして外部化される。


起動時に基礎部分のコードだけが動作し、自動的にインデックスのシーンを取りに行く。

基礎部分にシーンを持たないことで、軽量なエントリーポイントからいろいろできるようになった。


とにかく軽く。少なくともBloggerよりは軽量にしたい。無理か。


とりあえずindex以外のurlの分のhtmlも自動的に作成するようにしたい。(最終的にはnginxとかでアクセス時に生成すればいいような気がしている。

CMSっぽい物体なのに404を飲み込めないのやだな~っていうのがどうしてもある。


制約

シーンとその内容を自動的にAssetBundleにするのに、名前的な制約を使っている。

インデックスシーンは消せない。

今の所ほかの場所から特定のページをダイレクトに読み出す、っていうのができない(想定はある。



想定しているできたらいいな


リンク

外部リンクからでも該当のリソースだけを取得するように仕向けたい。これができると管理が楽。

ぶっちゃけ複数のシーンに対応するhtmlを置いて、CDNのそこにヒットしたらどっちにしてもjsが落とされ、

jsからはどこのurlから読み出されたのかが把握できるようになっているのでいきなりそのページ表示するのは可能。


必要なのはシーン単位でのhtmlジェネレータ。



軽量化

初動で1MB切りたい。WebAsmとかが来たら、なんとかなるかな~っていう楽観的な気持ちもあって、こういうのをつくっている。



HTMLのサイトと同じような触り心地

現状、UnityでのWebGLコンテンツはいろんなユーザーのイベントを吸い込む性質があるみたいだ。


command + Qとか、スクロールとか。

勝手にすいこまれてるんでどうしたもんかなっていう感じ。


文章とかコピペしたいじゃないですかー~~っていう。

スクロールバックとかちゃんと効いてほしい。現代の普通のWebサイトのフリがしたい。



ビルドの高速化

シーンの要素を調整とかUnity上でやった場合:10秒くらい

コードをいじった場合:1分くらい


自動的にAssetBundleに切り出した部分に関しては、ものすごく高速に変換できるようになった。

C#コードをいじった場合はこう、、なんだ、、どうしてもものすごいビルド時間がかかる。


1分とかかかる。


だめだ、、慣れてはいけない、死ぬぞ、、みたいな気持ちで見てる。





wrote 2016/02/13 17:49:56

AssetBundle使いつつlink.xmlになにか書くのは無意味、、ではなかった!!


概要

Unity 5.3.2p2 WebGLビルドの話題。

link.xml思ってたより意味なくて笑った。俺が間違っていることを望む。

→俺が間違ってた。



前提

目的は最初にロードされるシーンの軽量化。次のような手順で動かしてる。


・Scene Listにはローダーのみのほぼ空っぽのシーンを置く

・Strip Engine CodeをOnにする

・link.xmlに依存を書く

・AssetBundleに依存コードを使っているクラスを使う(Canvasとか


link.xmlにClass情報を記述し、AssetBundleで要素を取得、Instantiateした場合、link.xmlになにを書こうが無駄だった、みたいな話。



手順

link.xmlに特定のオブジェクトのClassId - nameを記述(下記)

<linker>

<assembly fullname="UnityEngine">

<type fullname="UnityEngine.MeshRenderer" preserve="all"/>

<type fullname="UnityEngine.BoxCollider" preserve="all"/>

<type fullname="UnityEngine.MeshFilter" preserve="all"/>

<type fullname="UnityEngine.Canvas" preserve="all"/>

<type fullname="UnityEngine.Sprite" preserve="all"/>

<type fullname="UnityEngine.CanvasRenderer" preserve="all"/>

</assembly>

</linker>


WebGLビルドで、特定のオブジェクト(Canvasなど)をAssetBundleから読み出した際に、link.xmlに対象クラスが入っていても、コードがアタッチされない。


The referenced script on this Behaviour is missing!

というエラーが出る。ちなみにブラウザ上だけ。



本来なら、例えばCanvasなら、デフォルトでコンポーネントに含まれている要素があって、それが展開されるはず、、なんだ。

そいつがmissingになる。


で。解決方法はあって、「同様のオブジェクトを含んだものをビルド時のScene Listに含んでいるシーンのヒエラルキーに持たせる」とか。

たとえそのシーンでは使ってなくてもdisableにしておいても、ようは入れておけばいい。


これだけで全く同じ手順でもmissingが発生しなくなる。


、、、



いや正しいけどさあ

これが正解の一つであることは別にいいんだよ、だって「コンパイル時に使ってないコードは入らない」んだから。

WebGLをはじめとして、UnityはあとからAssetBundleとかでコードを足すことができるプラットフォームでもないし(できるのもあるけど無視する。


link.xmlに期待してたのは、まさにその「コンパイル時には使ってないコードを内包した状態でビルドされ、あとからそれを使用するのを許す」部分だったんだけど。

なんか書き足すとビルド時のjsに内包されてるっぽい増え方するし、やったぜって思ったんだけどさ。


なぜ実行時にmissingになるのさ。



一番マシな解決法が正攻法一発、しかも使ってないリソース足す方法で、なおかつ一番重量を食うっていう、、、ほら、、なんか泣ける。



結局link.xmlに書こうが書かまいが、シーンに入れておかないとAssetBundleからのロード時に無意味になる、、という感じで、

っていうかビルド時に含まれるならもうそれで良くて、、使ってなくても、、


link.xmlになにか書いても意味がなく、link.xmlとは一体、、という疑問がある。



ちなみに

ぶっちゃけUnityEngineのコード全部含んでもDL sizeは5.3MBとかだったんで諦めたよ。

そのうち改善 or 解明されるだろ。


お問い合わせにはすでに出しております。俺は無駄なFUDはしない主義なんで。



ここから追記

Unityにお問い合わせしたところ、自分が作っていたlink.xmlの書式に不足があったことが分かった。


before

<linker>

<assembly fullname="UnityEngine">

<type fullname="UnityEngine.MeshRenderer" preserve="all"/>

<type fullname="UnityEngine.BoxCollider" preserve="all"/>

<type fullname="UnityEngine.MeshFilter" preserve="all"/>

<type fullname="UnityEngine.Canvas" preserve="all"/>

<type fullname="UnityEngine.Sprite" preserve="all"/>

<type fullname="UnityEngine.CanvasRenderer" preserve="all"/>

</assembly>

</linker>



after

<linker>

<assembly fullname="UnityEngine">

<type fullname="UnityEngine.MeshRenderer" preserve="all"/>

<type fullname="UnityEngine.BoxCollider" preserve="all"/>

<type fullname="UnityEngine.MeshFilter" preserve="all"/>

<type fullname="UnityEngine.Canvas" preserve="all"/>

<type fullname="UnityEngine.Sprite" preserve="all"/>

<type fullname="UnityEngine.CanvasRenderer" preserve="all"/>

       </assembly>

<assembly fullname="UnityEngine.UI">

               <type fullname="UnityEngine.CanvasScaler" preserve="all"/>

               <type fullname="UnityEngine.Image" preserve="all"/>

               <type fullname="UnityEngine.Shadow" preserve="all"/>

               <type fullname="UnityEngine.Text" preserve="all"/>

</assembly>

</linker>


不足していたのはこの濃いグレーのとこの記法のUnityEngine.UIで、

なんていうかその、、こういう書き方してある資料にWebGL絡みだけ探してても遭遇できなかったのが辛い。

うーーん、、この、、、解決してよかった、、、



エラーについてわかった事

missingを起こしていた原因は、クラス情報が不足していたから、に他ならん感じ。


エラーには2通りのものがあるというのがわかった。



その1 該当クラスの記述がlink.xmlにないと、Could not produceエラーが出るやつ


例えばlink.xmlにわざと不足を出す(Canvasとか消す)と、

Could not produce class with ID 223.


みたいなエラーがでるタイプ1。



その2 該当クラスの記述がlink.xmlにないと、The referenced script on this Behaviour is missing! エラーが出るやつ


例えばlink.xmlに不足があると、

The referenced script on this Behaviour is missing!


みたいなエラーが出るタイプ2。こちらはIDが出ない。missing + 何がmissingか(Object名かな)が出る



link.xmlに影響されてるエラーが正直タイプ1しか無いと思いこんでいたので、ハマった。

思い込みはよくねーな。



どんな依存をしているかについて

実行時のエラーをもとに依存をわりだしていたんだけど、

よく見たらAssetBundle作った時のmanifestにclassIdが書いてあった。


で、まあ、使うAssetBundleのmanifestを全てぶち抜いてグチャッと混ぜてlink.xmlに正しく書いたらいけたという次第。



ということで

得られた知見としては2つ。


1.dependencyがlink.xmlに書いてないから発生するエラーは一種類じゃ無い。

2.AssetBundle作ったらmanifestには依存ClassIdが書いてあるからとにかく収集すればいい



うまくいった~~よかった。

wrote 2016/02/11 4:33:38

link.xml製造機


概要

UnityでのWebGLビルドはまだまだまだまだyack。今一歩。二歩、三歩。


UnityでWebGLビルドするのをリモートのマシンでガンガン回してたけど1分切るかどうかって感じで切ないのでボリュームゾーンだけ最適化を試みる。


strip engine code

で、strip engine codeのチェックを入れると、不要なUnityEngineのコードが根こそぎ消える。のでこれを使いたいが、

そのままだと実行時必要なコードももちろんないので、最低限必要なものをlink.xmlに書くことになる。


で、classIdからclass引くのが面倒なので、classId入れたらlink.xml吐くのを作った


これ。好きにして。

https://github.com/sassembla/UniCMS/blob/master/Assets/Backyard/Editor/ClassIdCollector.cs



メニュー項目を一個自作して適宜ぶっ叩くといいと思う。

例:

https://github.com/sassembla/UniCMS/blob/master/Assets/Backyard/Editor/Publisher.cs


[MenuItem ("UniCMS/Generate link.xml")]

static void GenerateLinkXML () {

var classIds = new List<int>{223, 108};

ClassIdCollector.ExportLinkXMLWithUsingClassIds(classIds);

}


ほぼ手動。この辺Unityが進歩していく過程で自動化されるに決まってて夢はない。

ただし面倒臭い手動の部分をどう単純化 + 自動化するかが楽をするためのコツなんでその辺。


ここから先は、UnityのWebGLの出力最適化に関するメモ。



strip engine code on/off時の動作

単純に、コンパイルから全ての未使用のunity engine codeを消すか否か。


BuildSettingsのWebGLのこのチェックが付いていると、build resultから全ての未使用のUnityEngineがらみのコードが消える。

ビルドは最速、生成されるjsも2.3MB程度になる。


ちなみにUnityEngineがらみ以外のものは入るんで、すべてのUnityEngineがらみのものを使わないで書けばそれはそれでいいような気がする。

Webブラウザのjsコンソールで動くゲームとか。なにそれ。


で、strip engine codeがonの時、UnityEngineの機能(GUIとか、Unity2DのCanvasとか)を使用しようとすると、実行時に次のようなエラーが出る。


Could not produce class with ID 223.

This could be caused by a class being stripped from the build even though it is needed. Try disabling 'Strip Engine Code' in Player Settings.


うん、class with ID 223ってのがないんだね。なんだよそれっていう。


ようはUnityEngineのコードをstripしきっているんでゲーム内で使ってるコードもないですよっていうやつ。

対象のclass with ID 223 っていうのを個別にjs変換に巻き込むことで対応できる。


こういうのBackgroundで動かしておいてくれると嬉しいんだけど。


Unityのドキュメントの方にも「どや? 辛いやろ?? 辛いよな??? 頑張るから」みたいに書いてあるんで、

多分そうなっていくんだろうな。



あくまで目安として。


build time size

strip on 100% 2.3MB

strip off 133% 5.2MB



link.xmlの効果の実験

単にビルド速度 vs 規模みたいな感じで、Assets直下にlink.xmlを書くと特定のクラスだけを読み込んで変換してくれる。

で、linkに書く内容の量と時間の伸びが以下


build time size

strip on 100% 2.3MB

link * 3 100% 2.3MB

link * 10 121% 4.3MB

strip off 133% 5.2MB


すっごくキレイにlinkする数を足すとビルド時間とサイズが増えていく。

実際にはビルド時間の誤差がそれなりにあるんで正しく比例するもんでもないと思う。


どのclassを読み込むかで違ってくると思うし適当すぎるclass選択してるんで全く正しくないと思うが、

まーー小さくしたほうが楽だ。GUI系のコードはわりと軽い傾向がある気がするんで嬉しい。


ちなみにビルドごとにキャッシュが効くのでは??って思ったが、

全然そんなことないからなこれ。Scalaのコンパイルのほうが速い(Cleanした後どうこうとは言ってない



ちなみに5.4 betaでは

b4でも特に何にも変わってません。速度も内容もサイズも。


まあいいや。

Unity使ってWeb作るのの30%くらいはUIが面倒臭いからなんで、そこが許容できるかどうか。あとは構造化と自動化とメンテナビリティ。



動的なクラスの追加

なんとかしたい、、、、なんとかならないかな、、、



wrote 2016/02/07 23:39:20

CoreCLRで遊ぶ


概要

RC2になっても破壊的変更してるの個人的には好きです。

以前触った時はまだmono依存があったんだけど、現在(2016/01末)はもうmono依存なさげ。


適当な開発環境としてMac OS Xを使用して動かしている。インストールとか環境整備含めてものすごく楽になった。

インストールとかは公式からいける。ただ2点くらいハマった。

公式サイト

https://dotnet.github.io


ちなみに絶賛破壊的変更中とのことなので、今だ!やれよ!!!みたいなことは言わない。



簡単な紹介

公式からpkgをDL、実行すると dotnet って名前のコマンドラインツールが使えるようになる。

あとは


// 現在のdirにプロジェクトのコードとか設定ファイル一式がダイレクトに吐かれる

dotnet new 


// project.jsonとかに書かれた依存性を解決する

dotnet restore


// ビルド

dotnet build


// ビルドと実行

donet run


みたいなコマンドを実行するだけ。

メッチャお手軽にMac上でも動くC♯による成果物exeを吐くので、いいぞ~~~。


スクリーンショット 2016-01-31 2.00.19.png



ハマったところ



OpenSSL入れた後リンクコマンド打っとかないとnugetとの通信でエラーしまくる


単にbrewでopenssl入れただけだとダメで、


brew install openssl

brew link --force openssl


linkしないといけない。ちなみにインストラクションの中にOpenSSLについてのリンクが2個くらいあって、片っぽはbrew installしてるだけだったんでハマった。

これやっとかないと、新規プロジェクトを作成するScaffoldっぽいコマンドで大量の通信エラーが出る。


はじめ、原因が思いつかなくてなんだこりゃってなった。



System.Threading.Thread入れたコードがコンパイルエラーに成るんでコミュニティの人たちのお世話になるなどした

dotnet newで作成されるプロジェクト、依存してるものをproject.jsonとかに書くスタイルで、デフォルドではproject.jsonは以下のようになっている。


project.json

{

    "version": "1.0.0-*",

    "compilationOptions": {

        "emitEntryPoint": true

    },


    "dependencies": {

        "NETStandard.Library": "1.0.0-rc3-23727"

    },


    "frameworks": {

        "dnxcore50": { }

    }

}


NETStandard.Library っていうのがmscorlibみたいな物体で、いろんな標準ライブラリを含んでるっぽい。


で、


次のようなThreadをダイレクトに使ったコードをコンパイルしようとしたらコンパイルエラーになった。

using System;


namespace ConsoleApplication {

    public class Program {

        public static void Main(string[] args) {

System.Threading.Thread d;

Console.WriteLine("Hello World2!");

        }

    }

}


/Users/tomggg/test/app/Program.cs(7,21): error CS0234: The type or namespace name 'Thread' does not exist in the namespace 'System.Threading' (are you missing an assembly reference?)


えっ ThreadがThreadingに含まれてないの??マジで???ってなったんだけど、

問題の切り分けがしたくて色々コミュの人らに聞いてわかったこととして、


・NETStandard.Library にはSystem.Threading.Threadは含まれてない(今だけなのかは知らん

・使うにはdependenciesにSystem.Threading.Threadを書き加える必要がある(書き加えてrestoreしてrunしたら素晴らしくまともに動いた


ということだった。

具体的にはproject.jsonに書き加えて云々すればよかった。あれかな、この辺はIDEがやる前提なのかな。


{

    "version": "1.0.0-*",

    "compilationOptions": {

        "emitEntryPoint": true

    },


    "dependencies": {

"System.Threading.Thread":"1.0.0-rc3-23727",

        "NETStandard.Library": "1.0.0-rc3-23727"

    },


    "frameworks": {

        "dnxcore50": { }

    }

}



Thread使ってみたいんだけどエラー出てなぜなぜ?って言いに行ったら、親身になって聞いてくれる人の一方で「は??Task使いなよ??」って言われたのすごく新鮮だった。

気持ちはわかる。Task便利。


ちなみにTaskはnamespaceがSystem.Threading.Tasks で、これはNETStandard.Library に入っていた。

ド畜生がァ



生産物

https://github.com/sassembla/TestCoreCLR


wrote 2016/01/31 1:27:29

週刊Automatineマガジン 4.コンディションの更新


概要

UpdateでAutoの更新が行われるが、コンディションの更新もそこで行われる。

ただし、newを使ってAutoを切り替えるときは要注意、みたいな話。


ここでは、「コンディションはどうやって変化するのか」というのを解説する。


Automatineは各TackにTypeとValueという値のペアをセットすることができる。

実行中、「このフレーム内ならこういう状態」というのを表現することができるというわけ。


で、じゃあ次のタイミングの時、Autoの状態はそれぞれどうなってるの?っていう。

・Autoを初期化した時

・AutoをUpdateする前

・AutoをUpdateした後


初期化時

Autoには3つの初期化方法がある。


1.newを使って初期化する

auto = new Auto<I, U>(frame, IValue)


2.Autoクラスのinstance method ChangeToWithoutInheritConditions(Auto<I, U> newAuto)) を使う

auto = auto.ChangeToWithoutInheritConditions(new Auto<I, U>(frame, IValue))


3.Autoクラスのinstance method ChangeTo(Auto<I, U> newAuto)) を使う

auto = auto.ChangeTo(new Auto<I, U>(frame, IValue))



なぜ初期化に3つも方法があるのかというと、「直前のAutoの状態を引き継ぎたい」というケースがあるため。


1, 2の方法は、直前のAutoの状態の引き継ぎを行わず、

3だけは直前のAutoの状態の引き継ぎを行う。



ぶっちゃけると、


・最初のAutoを作り出す時はnew

・それ以降のAutoを変更したり更新したりするときにはChangeToメソッドを使う


というルールで覚えてもらって構わない。理由はこのページで後述する。



で、状態の話なんだけど、

初期化ずみのAutoは、特例として、実行前にもかかわらずConditionを返すことができる。


new、ChangeToWithoutInheritConditionsメソッドを使ってAutoを初期化/更新した場合、

実行前のAutoは、無条件に0フレーム目のConditionを返す。


対として、

ChangeToメソッドを使ってAutoを初期化/更新した場合、

実行前のAutoは、直前のAutoのConditionを返す。



この、メソッドによるautoの更新の特性の違いは、実際に使用する際にかなり顕著に出てくることになる。

具体的には、autoを更新する目的でnewやChangeToWithoutInheritConditionsメソッドを使うと、意図しない挙動を生みやすくなる。



Update前

Update前のAutoは、直前のUpdateで設定されたConditionを返す。


特に「初期化/更新したばかり」のAutoには特例があり、


new、ChangeToWithoutInheritConditionsメソッドを使ってAutoを初期化/更新した場合、

実行前のAutoは、無条件に0フレーム目のConditionを返す。


対として、

ChangeToメソッドを使ってAutoを初期化/更新した場合、

実行前のAutoは、直前のAutoのConditionを返す。



Update後

AutoのUpdateを行うと、そのタイミングに設定された動作を行う。

もし初めてのUpdateなら、ここで初めて、Auto自体にそのフレームでのConditionが付与されることになる。

ここに特例はない。

例えばその回でAutoの実行が完了する場合でも、最後のタイミングでセットされたConditionは正確に発現する。



初期化からUpdateにかけてのConditionを書くとこんな感じ


autoの初期化 or 更新から、Updateの流れを書き出してみると、次のような形になる。


(初期化/更新)

auto = new NewAuto<I, U>(0, IValue)


or


auto = auto.ChangeToWithoutInheritConditions(new NewAuto<I, U>(0, IValue))


or 


auto = auto.ChangeTo(new NewAuto<I, U>(0, IValue))


--- ---


(frame = 0)

// auto.Conditions()は0フレーム時の結果を返す(前のAutoのCondition or 新規Autoのデフォルト


Update(frame, UValue) (0フレームの適応をしてる


// auto.Conditions()は0フレーム時の結果を返す


frame++


--- ---


(frame = 1)

// auto.Conditions()は0フレーム時の結果を返す


Update(frame, UValue) (1フレームの適応をしてる


// auto.Conditions()は1フレーム時の結果を返す


frame++


--- ---


(frame = 2)

// auto.Conditions()は1フレーム時の結果を返す


Update(frame, UValue) (2フレームの適応をしてる


// auto.Conditions()は2フレーム時の結果を返す


frame++




注目すべきはframe = 0時のところで、


(frame = 0)

// auto.Conditions()は0フレーム時の結果を返す(前のAutoのCondition or 新規Autoのデフォルト


Update(frame, UValue) (0フレームの適応をしてる

0フレーム、autoの 初期化 か 更新 が終わってから一度もUpdateしていない状態でどんなConditionを返すのかが、

どの方法でautoの初期化をしたかで異なる。

new、ChangeToWithoutInheritConditionsメソッドを使ってAutoを初期化/更新した場合、

実行前のAutoは、無条件に0フレーム目のConditionを返す。


対として、

ChangeToメソッドを使ってAutoを初期化/更新した場合、

実行前のAutoは、直前のAutoのConditionを返す。



あっこのコピペ3度目だ。


状態だけを見ていくと、違いがわかりやすい。



newかChangeToWithoutInheritConditionsを使った場合


auto = new Auto

auto = auto.ChangeToWithoutInheritConditions(new Auto)


--- ---

実行前のconditionは新Autoの0フレーム目

Update


実行後のconditionは新Autoの0フレーム目


ChangeToを使った場合


auto = auto.ChangeTo(new Auto)


--- ---

conditionは旧Autoの最後の状態


Update


実行後のconditionは新Autoの0フレーム目


太字部分の差が出る。


これは特に、autoの更新を行う際、

newやChangeToWithoutInheritConditionsを使うと

「うっかりUpdate前にConditionを取得して連続してないのが帰ってきて困る」みたいな問題を生みやすい。


なので、次のルールを鉄則にしておくといい。

・最初のAutoを作り出す時はnew

・それ以降のAutoを変更したり更新したりするときにはChangeToメソッドを使う


もちろん意図的に前のAutoのconditionを継がずに0フレーム目を出したい、というケース(猟奇的だ)に対応する場合、


単にnewで書くよりは、ChangeToWithoutInheritConditions という長ったらしいメソッドを使うと、より意図を鮮明にできると思うのでオススメ。



wrote 2016/01/27 23:39:23

Automatine ダウンロードページ


Documents

まだ散逸している状態。この機能のドキュメントのリクエスト、とかあったらTwitterとかで。

週刊Automatineとか書いてあるのがそれ。


http://sassembla.github.io/Public/



Presentation

プレゼン資料(pdf)

https://dl.dropboxusercontent.com/u/36583594/outsource/AutomatinePresentation/AutomatinePresentation.pdf



Sample Projects

入門編 タイムラインでタイミングを決めてジャンプをする

https://dl.dropboxusercontent.com/u/36583594/outsource/AutomatinePresentation/StepUpAutomatine.zip


応用編 ブロック吐くドラゴンを跳ね飛ばすゲーム

https://dl.dropboxusercontent.com/u/36583594/outsource/AutomatinePresentation/AutomatineSample.zip



Unity Package

Old ⇅ New


https://dl.dropboxusercontent.com/u/36583594/outsource/Automatine_build_375.unitypackage


https://dl.dropboxusercontent.com/u/36583594/outsource/Automatine_build_406.unitypackage


https://dl.dropboxusercontent.com/u/36583594/outsource/Automatine_build_503.unitypackage


https://dl.dropboxusercontent.com/u/36583594/outsource/Automatine_build_588.unitypackage


https://dl.dropboxusercontent.com/u/36583594/outsource/Automatine_build_643.unitypackage


https://dl.dropboxusercontent.com/u/36583594/outsource/Automatine_build_982.unitypackage


https://dl.dropboxusercontent.com/u/36583594/outsource/Automatine_build_983.unitypackage


https://dl.dropboxusercontent.com/u/36583594/outsource/Automatine_build_1178.unitypackage


https://dl.dropboxusercontent.com/u/36583594/outsource/Automatine_build_1247.unitypackage


https://dl.dropboxusercontent.com/u/36583594/outsource/Automatine_build_1293.unitypackage


wrote 2016/01/26 16:35:34

週刊Automatineマガジン 3.リアルタイムに実行記録を見る


概要

(実装途中です。)


動作したタイミングとかを再現可能にする。吐き出したタイミングでのversionを持たせればいいかな、、

頭にversionを書き出しておくと合致しそう。




動的なログから動作を追う

エディタだったらjsonか何かを書き足す。行情報だといいのかな、、



Autoの起動タイミングで、特定のメソッドを実行すればいいよね

Open Auto

FocusToFrameすればいい。


んだけど、んーーー除外をどうしよう。

wrote 2016/01/24 18:32:39

週刊Automatineマガジン 1.AutomatineでのCoroutine


概要

毎号集めても何もない。ドキュメント作る時の備忘録。

今回は、AutomatineでのCoroutineの指針と、Coroutineで扱うパラメータ解説。



Coroutineの指針


Coroutineを超えてパラメータを扱いたい、、という時にはInitialTypeParamのパラメータを使おう

1.ロックオン

2.ロックしてあるやつを殴りに行く

こういう時には、InitialTypeParam自体や、そのプロパティ、値に「ロックした敵」というパラメータを持つといい。

実行中の各Coroutineでインスタンスを共有できるので、ロックした敵があったらそのIdを使って~みたいな書き方ができる。


Autoを超えてパラメータを扱いたい、、という時にも、contextのパラメータを使おう

初期化時に渡すと楽。


var context = new Context();

auto = new Something<Context, Other>(frame, context);


Coroutineは部品のように細かく分けて作ってもいいけど、大雑把に作って後で割るのもOK

e.g. 

一番近い敵の方を向く

敵まで歩いていく


最初はゴチャッと作っちゃっても問題ない。

e.g.

一番近い敵の方に向いてそのまま歩いていって殴る


ただし、名前とコメントをつけるようにしよう。


Coroutineの役割の分解は、コードがあんまり分散してないので、あとで簡単にできる。

まずは動くものを作って、そのあと切り分けるのがカンタン。



Coroutineで扱うパラメータ解説

Coroutineの初期値とパラメータについて

Timeline上に複数のTackを置いた場合、そのTackについているCoroutineが順に実行されるわけだが。

実行されるCoroutineには、次の2つのパラメータが入る。


1.initialParam、すべてのCoroutineから参照/設定ができるパラメータ

2.updateParam、auto.Updateの度に更新されるパラメータ



1.initialParam、すべてのCoroutineから参照/設定ができるパラメータ

new時にInitialParamTypeで型指定、initialParamとして渡せる値は、


・Autoのnewの時に、全Coroutineへと渡るパラメータになる

・全Coroutineからの変更が可能


という特性を持っている。


具体例として、次のようなAutoを初期化するコードがあると、


auto = new Auto<string, int>(frame, “初期値”);


InitialParamType には string型がセットされ、コンストラクタの第二引数 InitialTypeのパラメータにもstring型の値が入っている。



こうすると、このAutoのすべてのTimelineのすべてのTackに対して、Coroutine動作時に渡されるパラメータとして “初期値” という文字列が入る。


public partial class RoutineContexts<InitialParamType, UpdateParamType> : RoutineBase<InitialParamType, UpdateParamType> {

public IEnumerator TheCoroutine1 (InitialParamType initialParam) {

// ここで、initialParamの型は string になっている。 キャストして取り出すことができる。

var str = initialParam as string;


// この値は、このTimelineにセットされているどのCoroutineでも、そのTimeliineが所属するAutoを初期化した値になっている。

if (str == “初期値”) {

// true.

}

yield return null;

}

}



もし、InitialParamに自分で定義したクラスのインスタンスを入れた場合、そのインスタンスはそのAuto内のすべてのCoroutineに引き継がれる。


次のような[パラメータのパッケージ]をクラスとして定義してInitialTypeParamとして使う場合、

public class Params {

public string message;

}


auto = new Auto<Params, int>(frame, new Params());


ここで new Params() したインスタンスが、そのAutoの中のすべてのCoroutineからアクセス可能になる。

どこかのCoroutineで変更を加えると、その変更は他のCoroutineからも参照、変更できる。


次のCoroutine TheCoroutine2で、Paramsインスタンスのmessageという変数に”hello!!”という文字列をセットすると、

public partial class RoutineContexts<InitialParamType, UpdateParamType> : RoutineBase<InitialParamType, UpdateParamType> {

public IEnumerator TheCoroutine2 (InitialParamType initialParam) {

var params = initialParam as Params;

params.message = “hello!!”;

yield return null;

}

}


その後に実行されるCoroutineからは、その変更が把握できる。


public partial class RoutineContexts<InitialParamType, UpdateParamType> : RoutineBase<InitialParamType, UpdateParamType> {

public IEnumerator TheCoroutine3 (InitialParamType initialParam) {

var params = initialParam as Params;

if (params.message == “hello!!”;) {

// true.

}

yield return null;

}

}


こんな感じで、initialParamには次のような性質がある。

・Autoのnewの時に、全Coroutineへと渡るパラメータになる

・全Coroutineからの参照、変更が可能



2.updateParam、auto.Updateの度に更新されるパラメータ

Coroutineには、this.updateParam, this.frame などのパラメータが定義されている。

これらの値はAutoのアップデートを行うタイミングでセットすることができる。

例えばこんなクラスを用意し、

public class Params {

public string message;

}


Autoを次のように初期化した場合、


auto = new Auto<string, Params>(frame, “初期化”);


UpdateParamTypeには、Params型を指定してあり、

この後に実行するauto.Updateで、第二引数としてParams型のインスタンスを実行中のCoroutineへと渡すことができる。


var updateParam = new Params();

updateParam.message = “World!” + frame;

auto.Update(frame,  updateParam)

frame++;

このUpdateでは、実行開始のタイミング or 実行中のすべてのCoroutineへと、updateParamが入力される。


先ほどのUpdateを実行すると、Coroutineの中のパラメータはこんな感じになる。


public partial class RoutineContexts<InitialParamType, UpdateParamType> : RoutineBase<InitialParamType, UpdateParamType> {

public IEnumerator TheCoroutine4 (InitialParamType initialParam) {

var updateParams = this.updateParam as Params;

if (updateParams.message.StartsWith(“World!”)) {

// true.

}


yield return null;

}

}


また、複数回実行できるようなCoroutineの場合、毎回実行されるたびにupdateParamが更新される。


public partial class RoutineContexts<InitialParamType, UpdateParamType> : RoutineBase<InitialParamType, UpdateParamType> {

public IEnumerator TheCoroutine4 (InitialParamType initialParam) {


while (true) {

var updateParams = this.updateParam as Params;


Debug.Log(“updateParams.message:” + updateParams.message); // updateParams.message:World!フレーム数 (フレーム数部分は変動


yield return null;

}

}

}


ざっくり書くと、Updateを行うと、実行状態になった全Coroutineにその値がセットされ実行される。


auto.Update(frame, obj) ――> CoroutineA {this.updateParamにはobjが入っている}

――> CoroutineB {this.updateParamにはobjが入っている}

――> CoroutineC {this.updateParamにはobjが入っている}



Coroutine中の定義済みの値には、次のものがある。


・int frame

Update関数で入力したframeが入る。


・UpdateParamType updateParam

Update関数で入力したupdateParamが入る。


・loadCount

このCoroutineの実行回数が入っている。初回0。



まとめ

Coroutineに入ってくるパラメータ、

・一つのインスタンスをひき回せるInitialParamType

・毎フレーム更新されるUpdateParamType

の2つがある。


必要に合わせて使うといいと思う。





wrote 2016/01/23 3:56:43

週刊 Automatineマガジン2. Changerを使う


概要

ゲーム作ってて、操作する対象がいて、アイテムとか敵キャラがあって、

じゃあ敵キャラに攻撃だ! おやっこの敵キャラ複数のプレイヤーから殴られてるぞ?!とかあって、

フラグを持って状態判断するのは簡単、、なんだが、


「フラグの数がアババババばばば」

「えっこれとこれどっち優先すんの?」

「排他ァァぁ!?? もしかして排他ですかァァァァ!!??」

とかがある。


Automatineはこの辺に対して、Changerというものをもって挑む。



基本概念

殴られて死んだなら「お前もう死んでるから、次の状態はこれな」っていう

次の状態のラベルをもらえば良くない?


というのが基本の概念。



フラグを立てるのではなく、

・君、次は死んだ状態に行くといいよ

みたいなのをもらう。



この発想のいいところ

フラグの上げ下げが必要ない。次の状態の候補をもらうだけ。



この発想の悪いところ

その変化の候補ってどこからもらうの?とかその辺



Autoに対して、Changer = 可能性の定義 を行う

Automatineでは、Autoという単位が「現在の状態すべて」を持つようになっている。」


また、各Timeline、TackにはConditionを振ることができる。



で、

このAutoに、


「こういう状態だったら次はこの状態(別のAuto)に変わる可能性があるよね」


ていうのを列挙していくことができる。


1.「Conditionの、Damage.無敵 が ないフレームであれば、ダメージを受けた状態になる可能性がある」

2.「Conditionの、Damage.無敵 が ないフレームであれば、ダメージを受けて死んだ状態になる可能性がある」


1がダメージ受け中状態に移り変わる可能性のある条件、

2がダメージを受けて死ぬ可能性のある条件。


Autoに定義できる状態のみで判断して、こんな風に書き出せるわけだ。

1をChangerToDamaged、

2をChangerToDead、みたいに、名前と「次どんな状態になるか」をつけて、このAutoに保存することができる。


で、これをChanger(変化させるもの)と呼ぶ。

Autoにこれらを定義できることで、「別のAutoから見て、どんな変化の候補があるか」というのが作り出せた。


実際に使うとしたらこんな感じ。



実用Changer

次みたいなシチュエーションで使える。


1.PlayerがMonsterを殴った!


2.PlayerはMonsterのAutoからChangerを取得、ダメージ与えてHPが0になるのを確認したので、ChangerToDead をMonsterのAutoに積む。

複数の可能性があるならそれら全部を返してもいい。


3.Monsterは自分の行動のタイミングで、自分のAutoに積まれたChangerから、自分が受け入れなければいけないものを見る。

「わーい俺の番だぞ~積まれてるのは、、あっ死んだぞっていうのが積まれてる、、俺死んだのか、、」


4.ここで、Monsterは「死んでる状態」に移行する。

ざっとこんな感じ。


この方法のいいところは、hpフラグの確認をしているのがPlayer=殴った側で、殴られた側に可能性を積むだけで、予約が済んでいること。

受けた側がHPを確認する必要すら無いかもしれない。


(ネットゲーとかで殺したどうのとかする場合、この判定をサーバ側でも行えばいい。間違ってもクライアント側だけでやっちゃダメ。)

(実装を分割して、判定はサーバからのみ、とかにすれば良い。)




wrote 2016/01/23 21:18:48

How to use Automatine (、、、英語だな、、、)


概要

月が英語読めてよかったですね。古い。


AutomatineっていうC#で書かれたタイムラインアクション編集ツールを作ってて、

いい感じのとこまで来たので x生贄 oテストユーザ を募集するつもり。


こんな感じのアレです。

automatine0.gif

試してみたい人は自分のTwitterとかまで連絡してね。




簡単に言うと何

「ボタン一発押したら一番近い敵の方に走って行ってダッシュ斬り、その後もといた位置まで復帰」

みたいなのを次のような画面でセット、編集できるようになるツールと実行コード生成器。

automatine1.gif


こういうのコード上で組むと死にたくなるよね。



次のは、Timeline上の点にコード(Coroutine)を配置する様子。

automatine2.gif



機能

・タイムライン編集で適当に行動を配置

・状態の定義、実行時に取得、判定

・Coroutine配置して実行

・他




試してみたい人は自分のTwitterとかまで連絡してね(二度目)


wrote 2016/01/21 2:23:28

MacBook Restoreした


概要

年明けたのでやってみようシリーズ。



入れたもの

homebrewとかその辺はいつも通りとして、


TermHere(FinderのpathをTerminal.appで開くやつ) と、VSCodeHere(Finderのpathに対してVSCode開くやつ) を入れてた。


スクリーンショット 2016-01-02 0.27.39.png


特にVSCodeHereは便利だ、、、UnityのプロジェクトとかをフォルダからD&Dとかせずに一発で開ける。

VSCode自体がちょい重いが。



TermHere

https://github.com/sassembla/TermHere


VSCodeHere

https://github.com/sassembla/VSCodeHere




wrote 2016/01/01 20:25:35

locust使ってみる


概要

http://locust.io



install

pipでも入れられるんだけど、大変な量のエラーが出るので諦めてeasy_install。


sudo easy_install locustio



sudo locust -f job.py --host 127.0.0.1:80  --port 8000


で、サンプル的なjob.pyはこんなの。

from locust import HttpLocust, TaskSet, task


class WebsiteTasks(TaskSet):

    def on_start(self):

        pass

        # self.client.get("http:127.0.0.1:80/"

        #     , {

        #     "username": "test_user",

        #     "password": ""

        # })

    

    @task

    def index(self):

        self.client.get("http:127.0.0.1:80/")



    # @task

    # def about(self):

    #     print("b")

    #     self.client.get("/")

    #     # self.client.get("/about/")


class WebsiteUser(HttpLocust):

    task_set = WebsiteTasks

    min_wait = 1000

    max_wait = 15000



コマンドライン実行後、ブラウザで開く。



WebSocketを使いたい

easy_installでWebSocketのライブラリを足す

sudo easy_install websocket-client



jobファイルはこんな感じで。

from locust import HttpLocust, TaskSet, task

from websocket import create_connection

import gevent


class WebsiteTasks(TaskSet):

    def on_start(self): 

        ws = create_connection('ws://127.0.0.1:80/websocket_target_url')

        self.ws = ws


        def _receive():

            while True:

                res = ws.recv()

                print("res", res)


        gevent.spawn(_receive)



    def on_quit(self):

        self.ws.close()



    @task

    def index(self):

        self.ws.send_binary("body")



class WebsiteUser(HttpLocust):

    task_set = WebsiteTasks

    min_wait = 1000/15

    max_wait = 1000/15






wrote 2015/12/28 18:39:07

UnityEditor用のUndo入りGUIスケルトン TimeFlowShiki


概要

Unity Advent-Calendar 2015 12/10の記事です。

http://qiita.com/advent-calendar/2015/unity


前日の記事は @monryさんの「PostProcessBuildでInfo.plistを編集するための仕組みを作ってみた」でした。



TimelineっぽいツールのGUI作るの面倒くさかったので公開した

こんなのをGithubに公開した。

スクリーンショット 2015-12-09 23.22.02.png

TimeFlowShiki

https://github.com/sassembla/TimeFlowShiki


タイムフローシキと発音する。

Timeline状のGUIのスケルトンみたいな感じで、用途は特に限定していない。


面倒臭いGUIのところはなんかやっといたから、データ使うところとか、データに何か足すのとか、使いたい人が自由に頑張って。

どうせゲームごとにちょこちょこ違うでしょっていう。



TimeFlowShikiの概念

タイムライン状にデータを置いたり長さを変えたりするGUIツール。

4年くらい前、Adobeに絶望する以前はAfterEffectsを使ってたことがあったので、そのへんの感覚で作った

(Unityの操作系との相性を考えて調整していったら、結果全く似てない感じになった気がする)


Score、Timeline、Tack(鋲) の3階層からなる感じ。


Score

┗ Timeline

┗ Tack


┗ Timeline

┗ Tack, Tack



一つのScoreにN個のTimelineを持ち、

一つのTimelineにN個のTackを持つことができる。

Timelineにはtitleとかをセットできる。

Tackにはtitle, start, end, spanをセットできる。


これらのデータは、GUIでの変更発生時にJSONで保存される。

Assets/TimeFlowShiki/Data/timeflowshiki.json

で、あとはJSONデータをランタイムでどう解釈するか、とかで、まあいろいろできるのではないかな~と思う。

Editor側にコードを足していろいろクラス吐くとかもできると思う。



エディタとして作った機構とか

箇条書きで。


・Undo対応(だいたい全部の動作に対応してるんじゃないかしら)

・Tackの伸び縮み、移動、重ねる、とか

・右クリックでコンテキストメニュー出して、Timelineを追加したり、Tackを追加したりできる

・Score, Timeline, TackのTitle設定

・Scoreの最上部にこのフレームに位置してるTackが俯瞰できるミニバーみたいなのが出てる

・スクロールで無限に右にいける

・カラフル設定(TimeFlowShikiKitGUISettings.cs/RESOURCE_COLORS_SOURCESの封印を解くとカラフルになる

スクリーンショット 2015-12-09 22.27.09.png

・カーソル上下左右でTackとかTimeline上を移動できる

・画像素材はすべてAssets/TimeFlowShiki/Editor/GUI/Res に入っている



ライセンス

MITなんで適当につかってやってください。

デザインとかダサいんでどんどん手を加えちゃったりするといいんじゃないか!!



wrote 2015/12/10 00:00:00

UnityEditorのUndoで気をつけることファイナル


概要

ほぼすべての人類に無関係。十分にロックイン事案。


Undo自体の実装の話はこっち。

「UnityEditorのUndo/Redoシステムについて【解決編】【最新】のコピーそして完結」

http://sassembla.github.io/Public/2015:09:17%203-14-23/2015:09:17%203-14-23.html

今回は、なるべく面倒臭く無い方法で、管理される側のオブジェクトに辞書を使ったりする話。

端的にいうと最後、値をどう持つかで、値の保持にDictionaryを使うと辛い部分があった。

これはScriptableObjectを全開で使ってても、実際のデータの型に関連するので、例外なくつらい。


Dictionaryを使うと何が辛いのか

辞書 Dictionary をデータ構造に使うと、その部分がUndo効かない。

抽象的なコード書くと、


Undo.RecordObject(this, “Update Dictionary Value”);

myDict[“key”] = “val”;


みたいなことをしても、myDictの値がUndoできない。というかUndo履歴に乗らない。

[SerializeField] 振ってても、これは別の理由で効かないっぽい。

同様にList<string> とかに対して、


Undo.RecordObject(this, “Update List Value”);

myList.Add(“val”);


とかやると、これは効く。



違いを追っていく過程でわかったこと

いろいろ試していたら、次のようなことがわかった。完全にやっくしぇーびんぐ感があった。


・ISerializationCallbackReceiver とかはUndoとは関係無いっぽい

(Undoにはserialize的な特性は必要でも実務として特定のserialize処理が走ることは無いっぽくてISerializationCallbackReceiver実装しても呼ばれない


・Dict -> List + List に分解するとうまくいく

Dictionary<string, string> -> List<string> keys + List<string> values に分解したら、Undoは働いた


・調子に乗ってクラス化 + 型パラメータ化 -> 死ぬ 

型パラメータが入るとだめくさい。

例えば下記のような構成は死ぬ。


[Serializable] public class SerializablePseudoDictionary<TKey, TValue> {

[SerializeField] private List<TKey> keys = new List<TKey>();

[SerializeField] private List<TValue> values = new List<TValue>();

. . .


こういうの定義できると楽だったんだが。



結論

List + GenericならUndo対象にできるので、Dictionary + Generics -> List<string> keys & List<string> values と分解できるようなクラス作ってやると瞬殺できる。


実際AssetGraphで使うことになった。 辞書っぽいもの作ってもUndoに対応できる。

https://github.com/unity3d-jp/AssetGraph/blob/0.7.6/Assets/AssetGraph/Editor/Libs/SerializablePseudoDictionary.cs

抜粋。

using UnityEngine;


using System;

using System.Linq;

using System.Collections.Generic;


namespace AssetGraph {

/*

string key & string value only.

because generic dictionary class cannot undo.


write -> Add(k,v) -> new dict -> keys, values

read <- ReadonlyDict() <- new dict <- keys, values

*/

[Serializable] public class SerializablePseudoDictionary {

[SerializeField] private List<string> keys = new List<string>();

[SerializeField] private List<string> values = new List<string>();


public SerializablePseudoDictionary (Dictionary<string, string> baseDict) {

var dict = new Dictionary<string, string>(baseDict);


keys = dict.Keys.ToList();

values = dict.Values.ToList();

}


public void Add (string key, string val) {

var dict = new Dictionary<string, string>();

for (var i = 0; i < keys.Count; i++) {

var currentKey = keys[i];

var currentVal = values[i];

dict[currentKey] = currentVal;

}


// add or update parameter.

dict[key] = val;


keys = new List<string>(dict.Keys);

values = new List<string>(dict.Values);

}


public bool ContainsKey (string key) {

var dict = new Dictionary<string, string>();

for (var i = 0; i < keys.Count; i++) {

var currentKey = keys[i];

var currentVal = values[i];

dict[currentKey] = currentVal;

}


return dict.ContainsKey(key);

}


public Dictionary<string, string> ReadonlyDict () {

var dict = new Dictionary<string, string>();

if (keys == null) return dict;


for (var i = 0; i < keys.Count; i++) {

var key = keys[i];

var val = values[i];

dict[key] = val;

}


return dict;

}

}


お察しのとおり、read, writeに辞書化を挟んでるんで、使いやすいような気はあんましない。

Undo対象の数が少なかったのと、Undo動作自体を綺麗にまとめておくことができたので、実装と導入と改変は楽だった。


ただUnityとしか関係無い特殊な状況だ。


感想

試してないけどhashとかだとうまく動くんじゃ無いだろうか。


厄介なのは、Editor以外でもSerializable使っていろんなものをSerialize可能にすることができるんだけど、

これは結局ゲーム中でも使える手段だぜってところなんだけど、

・ListはOKでDictはダメ

・Serializableつけてもダメ

っていうのがある時点で、まあ、独自色強くなるんで、できうる限りゲームでDictのSerializeは使わないほうがいいだろうな、と思った。


ちなみにゲーム中( = 非Editor)の場合は、ISerializationCallbackReceiverまわりの関数が呼ばれるらしい。

Editorではそんなことなかったんで、まあ、はい。


無理にこういう[Serializable] + 独自Serializer実装するくらいなら、下記を実行するといいと思う。


a.Unityさんに殴り込んで「Serializableの有効範囲広げてや」って言う

b.[Serializable] を使ってDictionaryのSerializeが必要な状態を避ける、あるいはDictionary以外のものに対して[Serializable] を使う

c.[Serializable] を使わず自分で何かに変換する


b,cどちらの手段を選ぶにしても、Unityに「お前SerializeField効かない型があるの辛いぞ」っていう話をするのはアリだと思う。

自分からはします。




wrote 2015/12/04 17:56:48

Disposabilityについて


概要

技術に対しての投資の話、

「2年後に聞くリスト」っていうのを以前から書いていて、


あれは

「投資価値が無い気がする」「厄い」「2年後には存在してないだろうからそのときに聞けばいい。今やるのは時間の無駄」

「学ぶことがあったが使いたくはない」

みたいな物事についてした判断を書いたメモになってる。


今回話そうとしてる「Disposability」がない、やらんでもいいものを記録しておくやつ。


反対に、「Disposabilityが高い」っていうのがどういう状態か、っていうのをメモっておくつもり。

投資対象を選ぶとき、どんな基準で選ぶか、みたいな話。



Disposabilityとは

ざっくり言うと、「負債返済しないで捨ててしまいたい時の捨てやすさ」みたいなものだと思っている。

「それを使っていて、もしもっといいものが見つかった場合、どの程度の資産を移動して、この技術を捨てることが容易か」みたいなパラメータ。


このパラメータ Disposability が高いと、以下のようなことが可能だと思っている。

利益

1.Disposabilityが高いと、この技術や機構を捨てても、価値が失われない or 失われにくい or 失う部分を最小化できる

2.Disposabilityが高いと、技術的負債になりにくい(負債になってもサクッと捨てられれば、それはもっとも安価な解消法)



逆にこのパラメータが低いと、以下のような損害があると思っている。

損害

3.Disposabilityが低いと、この技術や機構と価値が不可分で、移行できない

4.Disposabilityが低いと、移行先にも同じような技術、機構を自分で再現する必要があって移行コストが高い

5.Disposabilityが低いと、移行先では技術や機構が再現できないので、技術的負債になっても返済するしかない


定義について言いたいことはほぼほぼ以上な感じで、あとはDisposabilityをいつどこで測るか、とか、判例的な判断基準をつらつら書いていく。


先に断っておくと、このパラメータは言語やプロトコル、プラットフォームには適応されないケースが多く、

エンジン、フレームワーク、ライブラリとかのレイヤーで、この判断方法をよく活用している。


ようは、「万人が使わない」みたいなものほど、Disposabilityで見たほうがいいんじゃないか、みたいな話。



いつDisposabilityを測るか

新しい何かを見つけて、まず触ってみてからでいいと思う。


よく「新しいものに飛びついていいのは選ばれた人だけ」みたいな話があってモンニョリするんだけど、

「いや一瞬でいいから触れよ、メッチャ面白い場合があるぞ」って思うので。


打率を気にする前にバッターボックスに立てよという感じ。


触って、なるほどこういうものか、ってトコまでわかったら、あとはDisposabilityを測るためにいろいろ知る作業に入る。


理解は経験に比例するので、「あっこんなことできるんだ!」っていうのと、

すぐさま内容をみて、「実装は、、オオオーー泥くせえ、、、クソの匂いがするぜ、、」 or 「あっ凄いこれでこんな事できるんだ素敵!!」って

判断するフェーズを踏んでも別に構わんと思う。


あとは「全体としては良いんだけどこの機能にだけは最低限依存したくねえ、、、」みたいなケースの時に、その使用を回避できるかどうかとか。

部分で嫌な箇所を回避できればそれはそれでいいよね。


とある技術、機構を使うぜ!って決めたあとにわかる事ももちろんあるんだけど、意図して測ろうとするとまたちょっといいのでは、という程度の話だが。


以下判例。



独自の機構を自前実装で持っているフレームワークとかはDisposability低い

学習コスト高い上にそこでしか使えない技術あって、みたいなFWだと、

損点として3,4,5全てに該当してベストオブ低Disposabilityを叩き出す。


スメルとしては以下。

・記法をはじめとして色々なオリジナリティある機能を内包、独自実装している

・その機能が今後プラットフォーム側とかに積まれる想定が無い

など。


どっかでも書いたけど、学習デブになるだけでそのままその特異性ごと闇に葬り去られるので関わらないほうがいいと思う。



Embeddedが強烈すぎるやつはDisposability低い

組み込み機構の能力が高すぎるやつは、それを他所で再現するのが大変そうで、ようは資産価値というかDisposabilityがめっちゃ低い気がしてる。

例えばコード全く書かずにGUIだけで動くやつ、とかは、なんていうかその色が強そう。


自分が書いた「コードじゃないやつ」を元に、同じ事をするのにどれだけの無駄な犠牲を払えばいいか、みたいな尺度。



思いついたら足す。



wrote 2015/11/21 16:52:08

iPad Pro向けのお絵描きツールいろいろ見てみた


概要

iPad Pro買ったのでお絵描きしてる。


広い。

軽い(ペンタブ持ち歩くより激しくマシ)。

ペンの追従性のMaxが異様に良い(Surface Proでは叶わなかった)。

楽しい。


試したAppと描いてみた絵一覧

これ以外にもこういうのもあるんで試せ、っていうのがあったら、Twitterアカウントまで連絡くれれば良いと思う。より良いツールと出会えると嬉しい。


Procreate

https://itunes.apple.com/en/app/procreate-sketch-paint-create./id425073498

Attachment-1.png

新、マイベストお絵描きツール。

レイヤーもあるしペンの操作も素晴らしく効くし、落ちないしデータ勝手に消えないし。

回転とかが非常にスムーズで素敵すぎる。



Paper

https://itunes.apple.com/us/app/paper-notes-photo-annotation/id506003812


旧、自分にとっての最高のツール。

絵を描く際は、ハサミでの部分消し、移動と鉛筆だけ使ってる。

レイヤーと回転が欲しいけど、サクサク描く分には困らない印象。見てくださいこの完璧な鉛筆傾け+筆圧の入りと抜け。

Drawn - 3.png



Adobe Sketch

https://itunes.apple.com/us/app/adobe-photoshop-sketch-expressive/id839085644


これの鉛筆ツールが凄い。移動速度、筆圧から濃淡への反映速度、ともにパーフェクト。


弱点が何個かあって、

ひとつは、レイヤーがないこと。

次に、UIの構造が頭おかしいこと。

そしてUndoを勝手にまとめやがること。

あと、よく落ちること。

最後に、落ちた際のデータが全部消えたことがあること。


ああ、、残念、、、さすがAdobe、、、絶対に金払って得るような信頼性じゃねえ、、、無償でよかった、、


でも鉛筆ツールは気持ち良い。

Paperの次点になったのは落ちる頻度がスッゲー高いから + Paperのハサミに比べて消しゴムを使うのが辛いから。

Image-1.jpg



Sketches

https://itunes.apple.com/us/app/tayasui-sketches-draw-paint/id641900855


かなり具合が良い。筆圧にも対応している。ただしTilt(傾き)がないっぽいのと、ドキュメントの吐き出しとか複数ドキュメントの扱いとかがさっっぱりわからなかった。

理解できればすごく良いツールなのでは、、!!!


いろんなツールを課金で扱ってるので、もっと時間かけても良いかもしれない。レイヤーもある。

1時間お試しで機能を使えるのがすごく良い。


ツール数がすごく多いんで、、、総額幾らになるんだろうな?

シャーペンでカリカリ書いてたんだけど、濃淡の設定がよくわかんなかったので淡ーく書いてからサインペンっぽいのでサクサクした。

IMG_0009.PNG



Pixelmator

https://itunes.apple.com/en/app/pixelmator/id924695435


Mac版も存在するお絵描きApp。レイヤーが自由に使えたりするし操作性も良い。クセは強いけど。

で、、、、まだペンに対応してない。筆圧とかは反映されてない感じだった。


その辺対応したらすごく良いと思う。ただやっぱり異様にクセが強い。

操作系のショートカットとかがしっかりしてればいいんだけどな、、、

イメージ.png



Autodesk SketchBook

https://itunes.apple.com/us/app/autodesk-sketchbook/id883738213


Pro Toolsってのが別売りだったのでそれも入れつつ。

っていうか入れないとレイヤー使えなかったんで。

で、、、そもそもタッチとかペンの入力が怪しい。チョンっと書いた点とかがすごく遅れて小さく出る。


ドキュメントのサイズが1000pixちょっとになってて、ようはRetina対応されてない感じ。

こいつだけ、この記事書いてる時に画像サイズを変更してない。1280 x 959とかだった。

Undoのショートカット誤爆しまくるし、筆圧は入ってる、、、ような気がするんだけどピーキーすぎて、書いてて気持ち良さがない。

今後に期待。

→ドキュメントサイズとかはちゃんと設定するところがあった。が、サイズ限界が小さくて操作しづらくて挫折した。

1__#$!@%!#__Attachment-1.png


とりあえず以上。



唐突だがすべてのお絵描きAppに望むこと for iPad

UndoとRedoのショートカットをうまいこと考えてくれ、、、


Paperのやつが操作法変わって使いづらくなったとはいえすごく良い。

次点でSketchesのやつがまた良い。

最悪なのは、Undoボタンを押さないとUndoできない(ないしはそうせざるを得ないくらいショートカットの反応が悪い

褒めてないやつのUndo操作は地獄のようだった。



消しゴムとタッチインターフェース

Paperのハサミツールが結構最高で、これについてちょっと書いておく。


Paperでは範囲選択(Lasso)で、選択した範囲を任意の場所に移動することが可能になっている。


正直これってものすごく使いやすくて、汚くなった箇所とかを選択、ポイ捨て、っていうのがすごく高速に、かつ範囲指定を細かく実現できる。

マスキングとカットを同時にできる感じ。


消しゴムだとこうはいかない。

消すっていうのをストロークでやると、けっこう面倒臭いな、っていうのが、iPad Pro + ペンで描画周りが素晴らしくなってからの感想。







wrote 2015/11/14 22:16:33

有料Assetがパクられ無料で3,000DL/月くらいされた話してきた


概要

ここで、

Unityアセットリリースミーティング

https://picos.doorkeeper.jp/events/32098


有料で販売していたAssetが、チューゴクのSNSとかで無料になってDLされてた話をしてきた。

DLの数字は2014年のなかとかその辺。

これ。

SublimeSocketAsset

https://www.assetstore.unity3d.com/jp/#!/content/8003

MacとかでSublimeText使ってコード書きやすくするやつ。

最近はVS Codeとかが出たおかげで、これ使わなくてもかなり楽にコード書けるようになったのでよかった。



気づいた経緯

ググったらDLできたぞって買った人からメールでもらった。


ググってみると

スクリーンショット 2015-11-08 16.34.46.png

torrent.png


なるほど。


もう記録残してないけど、チューゴクのSNSで

Chinese A:「こんなのあったよ~無償で配っちゃるぜ!」

Chinese B:「マジか、お前サイコーだな!」

Chinese A:「せやろ?」


みたいなやりとりでzipがアップされてるのもあって、それに数百のいいねがついてたりして、

こいつら全員死ねばいいな?って思ったりした。


一時期、Asset名でググるとpage 3くらいまでがStoreのやつ + 違法アップ、みたいな感じで辛かった。

ちな局所的にDL数出してるところがあったんで、その数字が3,000/monthくらいだった。



何がイヤか

儲からん

まあ前提として。


正しいユーザーからのお問い合わせなのか?

タイミング的に最悪だったのが、やたらお問い合わせがくることがあった事。


お問い合わせがきて、正しいユーザーかどうかわからんままお話する、みたいなのが発生する。

これが一番腹が立った。


「お問い合わせしてきたこの人は、正しいユーザー、、なんだと思うんだけど本当かな」

って、人を疑わなければいけないっていうのは、最悪の経験。



対策ゥ?

何手か、、

0.Googleさんとかに「俺様は権利者だ、こいつら違法アップローダどもは不正なことをしている、殺せ、いいな」って送る

1.購入記録を元に初回起動、あなたは善人ですか?ってやる(作るのも使うのもウザい

2.起動時問い合わせ(作るのも使うのもクソウッザい



最終的に選んだ、絶対殺す策


1.メジャーバージョンをあげる


「そうだ、メジャーバージョンをあげよう」


パクで出回っているやつを過去にする。

ちょうど互換性破壊するような調整入れるタイミングだったんで、問題なく。

あと無料で試せる版の開発をしたりした。そしたら結局ユーザー増えたので、まあよかったのかなっていう。

でも開発動機として不満は残るので、今後は自分では一切考えないようにしようって思った。殺し屋でも雇おう。

2.検索から殺す

検索からの抹殺は主に自分の精神の健康のために行った。

このへんはUnityとかにお願いしても、「権利者以外がシャシャリきてるんじゃねえよ~」ってUnity側が追い払われたりするんで、

不快だがゴミどもは自分の手で殺そう。



結果

観測しないことにしたのでよく知らない。

関係なくバージョンが上がり、それらの質はよくなったので、DLは増えた。



おまけ1:お問い合わせ言語ランキング

最近はメッキリ減ったけど。


1位.英語(60%over)

2位.中国語(10%くらい)

3位~ 韓国語、日本語、ドイツ語、ロシア語、


中国のひとは、こっちが日本人だとわかると「日本語訳もつけてみた!みやすいと嬉しいな、どうかな」みたいな感じで

日本語訳されてるメッセージ + 中国語原文、みたいなのを送ってくるひとが数人いた。



おまけ2:避けたほうがいいAsset名

すでにWebで著名なフレームワークとかがある場合、


たとえば Ruby on Rails とかと被るのは避けよう。


名前がバッティングしようものなら本気で検索に引っかからない。

避けよう。


絶対に避けよう。


絶対に。




AssetRails

https://www.assetstore.unity3d.com/jp/#!/content/27672


wrote 2015/11/08 16:28:10

ゲームデータのPreloadabilityを考える


概要

特にUnityに限る話ではなく、どんなエンジンで作ろうが言えそうな内容。


こんな仕組み作って使ってみたよ、っていうのを基礎として、俺の考えた最高のPreloadabilityの話をする。

・Client側のプラットフォームがゲームをDLしようと試みる

・データをDLする

・実際に遊べるようになる

っていう動作の間に、ユーザーが実際にその素材を必要とする前に、どこまで何をDLさせるか、っていうのを効率良く制御することを考える。



前提

ある程度は運用スタイルを含んだお話になる。


通信方法については特に指定しない限りはHTTP1系を使う。


また、章の中では動作するサンプルコードを元に話をしていくが、このサンプルコード、特にエラーハンドリングとかは考えてないので、

実際に使ってみてどんな目に合うかは君次第だ!!



Preloadのモチベーション

次のようなモチベーションを掲げておく。


1.最速で遊んでほしい

ユーザーがゲームをDLしてから、すべての素材をDLしてからゲーム開始、、ってやると、無限の時間がかかってしまう。


ムービー流したりいろいろ、、ユーザーの我慢を促進することは出来るっちゃあ出来るんだけど、

「そもそもそのリソースを俺が目にすることがあるのだろうか?」っていう素材を、遊ぶ前にDLさせるのはこう、、なんていうか、、辛いよなっていう。

あとムービーは飛ばすしストーリーはスキップするよな、設定なんかよりカタルシスとかそういうのが欲しいわけだよ(暴言)


2.ユーザーが端末内に持ってる素材をできるだけ少なくしたい

ユーザーの端末内に大量の素材を置いておくことになる、、ので、まずそれをできるだけ小さくしたいよな~っていうのはよくある欲求だとおもう。



3.リリース後はサーバー側からコントロールしたい

ゲームが一度世に出ると、そのあとユーザーの端末と管理側を繋ぐのは通信APIとかだけになる。

ユーザーが保持している素材について、サーバー側が何かできるといいなっていう感じ。


ユーザーが手元で動かすゲーム自体をUpdateする、という方法もある。

個人製作のゲームの場合は主にサーバーを持たないようにしたいな~ってなると思うが、

この章では、「もし機構を最小化できたらどんな感じか」というのを念頭に、そのメリットを書いてみようと思う。


まあ課金機構とかいれようものなら、どこかにサーバ置いて、、ってなっちゃうんだけどさ。

課金に関してはまあ、、AppleとかGoogleにお任せ機構が選べるならそれも良し。



これらが叶えば、ユーザーは常に必要最低限の通信をして、ゲームのプレイができそうだ。


願望が整ったところで、その願望をどのように叶えればいいのか、を書いていく。










っていう記事をUnibook4向けに書いてます。

wrote 2015/10/31 16:54:29

フィードバックはともかくVRに手を突っ込むとどうなるかみたいなのの感想


概要

UnrealFest2015でBulletTrain触れたので良かった。


これ。

https://atnd.org/events/70010


Oculus Touch触ってて、センシング、追従性、そこから得られる感性みたいなものの分解をしてみたかったのでやってみた。



ちなみにBulletTrain、男の子の夢いっぱいバカいっぱい、


左手にアサルトライフル右手にもアサルトライフルみたいな感じでマルチターゲットな感じでこうね、もうね、

アホかというくらい面白かったですよ。


敵が撃ってくる銃弾はすべて「止まって見える、、止まって見えるぞ、、!!!」みたいな感じでドラゴンボールぽい「全弾つまんで返す」みたいな遊びができる。

この不平等よ。オレツエー感よ。

実現してる源はOculus + Touchの合わせ技なのだけれど、

ぶっちゃけOculusの視界よりもTouchの存在のほうが世界的にヤバイのでは、、??っていう気がしている。



触る前に考えてた事

次の要素についてどんなもんなのか知りたかった。

1.位置について

センシングの基礎みたいな。


2.向きについて

何というか没入感の助けになるのかなって。


3.行為について

エンタテイメントで考えたらどうなってるの?みたいな。



触った後に考えること

追加で、次の要素が観れた気がする。


4.手とゲーム操作関連の脳内マッピング

実際に動かして発生した齟齬とその解消。


5.掴み範囲の緩さ

とっても難易度に関わりそうなところ。


6.体験結果と攻略

あまりに好き勝手できて面白くて夢から醒めなくてハマった話。


最後の攻略ってなんだよって感じなんだけど、後から俯瞰で考えてみたらやってた事は攻略だった。



1.位置について

手、特に手首から先だけなんだけど、位置トラッキングでミスったことは全くなかった。

認識と精度が異様。移動に関しての遅れはほとんど感じられない。

認識できなければ差はないみたいな。どっちかっていうとゲーム内での所作の何をサポートするのかがすごく大事な気がした。

ゲーム性とのバーターで発生している「つかみ範囲の緩さ」みたいなのも手伝って、

ものを掴むための位置の判定の緩さから感じている快適さも結構ある気がする。


位置トラッキングの精度が高いせいもあるけど、これは確かに自分で持ってた銃を上に投げて再キャッチとか「楽に」できるわ。

もし二度目やるなら、適当なテレポート場所に銃いっぱい投げてあつめて、そいつをジャグリングしながら打つとかもできるかもしれない。



2.向きについて

位置と同じ精度で認識されてる感じ。

特にAK?みたいなアサルトライフル2挺拳銃してる時にもその角度の反映が見事だった。


投げる動作については、リリース時の向きとか加速度が関係してるのとしてないののみがあって、角度はそれらと無関係だったので楽だった。

例えば刀みたいなのもってて横殴りだとダメ、とかだったらもっとセンシティブに観れたと思う。



3.行為について

ゲームっぽい仕上がりなので、手を使った以下の行為があった。


移動系

・手元のボタンでテレポート開始行為

・腕が向いてる方向でテレポート先選択

・ボタンを離した時に選択されているポートに向けて移動


動作系

・外界にスロウをかける(テレポート開始と被せてある)

・落ちている/飛んでくるものを掴む

・掴んでいる銃を打つ

・掴んでいるものを離す/飛んできてたものの場合離すときの加速度とかで効果が変わるものがある


掴む/離す、っていう行為の対称性が微妙に多彩で、

たとえば足元に銃が落ちている -> 掴む -> 腕で向きを付ける -> トリガーで撃つ

敵の弾とかが飛んできてる -> 掴む -> 離すと飛んでいく or 腕の動作に連携して落ちたり飛ばせたり


上記動作が全部、競合・ロックせず実行できる。ようは「手」がもつ性能をすべて「同時」に発揮できる。


右手でスロウを発生させつつなんか飛んできてる弾丸を掴みつつ「誰だよこの弾、、あ、あのへんのやつか」ってやってる最中、

左手で構えた拳銃からはそいつに対して弾を吐けたりする。


コントローラでは無理。絶対無理。この同時処理。


同時処理って意味で自由度が恐ろしく高い。プレイヤーの理想値が出る。何をゲームしてるんだろう。


4.手とゲーム操作関連の脳内マッピング

前出の通り、同時操作の括りが既存のものに比べて格段に弱いので、自由度がものすごく高い。


なのでどんな動作の組み合わせでも考えて実行する価値がある。なんだろうこの選択肢の広さ。


この辺がこの環境に対して「慣れる」って呼ばれる動作なんだろうけど、

結論から言うと手っていうか機能限定されたロボットアームだと思うと順応がメッチャ楽だった。


んでさらに物理的な限界を考えないことでも楽しめた。

たとえばスローモーション化させながらでも手はめっちゃ速く動かせるので、飛んできてる弾丸をつまむのが大変捗った。


手といえば手なんだけど、自分の師匠がiPhoneとかのTouch操作見たとき言ってた「これはジェスチャーだ」みたいな言葉を思い出した。Forceを使うんだ感ある。

このへんはゲームに関して手を持ち込むときのアイデアにつながりそう。


今回は精度が無茶苦茶いいロボットアーム、って考えて、物理的な制約とかそういうのが吹っ飛んでやりたいことをやりたいだけやるマシンになってた気がする。

また、「例えば自分の視界に見える手のメタファの見え方が違ったらどうだったんだろう?」みたいな新しい疑問を生んでいる。



5.掴み範囲の緩さ

このゲームというか、手での動作を支える根幹っぽかった。

どの程度緩いんだろう?とか事前には想像してなかったんだけど、立ってる位置から手の届く範囲として、実際に手のある位置から20cmくらいはサバを読んでる感じ。

手前=前方に関してはさらに緩そうだった。


このへんが調整要素としてとても心地よい感覚を生んでる感じだった。

このサポートが無いと、「掴みたいけど掴めない」っていうのは手が出てるが故のストレスになり得る感じがする。調整してみたかった。


ようは、この形のゲームでなくとも、なんか「掴めそうで掴め無い」っていうのはすごくストレスになりそうだな、って思った。



6.体験結果と攻略

チュートリアルでテレポートとか手の動きとかを学べる。これをOculusのセットアップからTouchのセットアップとか全部順にやってくれてるのでそりゃお時間いただきますわという感じ。


スタッフの方これはめっちゃお疲れさまです。


物理法則無視して、義体になったらこんな感じなのかなあ、みたいな感じで動いた。


具体的には以下のようなプレイになった。

・歩いてる敵キャラを自由に目視

・目に見えた弾丸は視界動かしながらでも摘める->撃ったやつかそのへんにいる奴に返せる

・銃が落ちてるの見えたらそこにはテレポートできるはずなので適当に返しながら移動先を探して移動

・弾切れとかは音で判断(ぶっちゃけサイトを見ないでも武器が潤沢なのに気付いたので撃っちゃ捨て撃っちゃ捨てできた

・それらを両手で適当に実行できる


これが、、自由か、、、みたいな感じになった。

何をゲームしてるんだろう。


これはゲームを遊ぶんじゃなくて自由を遊ぶみたいなフェーズに入った気がする。ゲーム一度ぶっ壊れそう。

ぶっちゃけOculusの視界よりもTouchの存在のほうが世界的にヤバイのでは、、??っていう気がしている。(二度目


まとめ

ゲーム終わってOculus外したら「最速クリアです」みたいな話されたけどびっくりしたのは目の前にゴロマンさん居たことだった。

そういう3Dコンテンツかと思った。


以上。

wrote 2015/10/18 13:43:03

akeytsuをMacBookで使いたい


概要

これ。

https://www.nukeygara.com


まだまだ過渡期っぽいんだけど、モーションつけるためだけにBlender使いたくないな、、?っていう思いに駆られたので、いろいろ試してみてる。


結論から言うとGPU的に無理だった。

サポートのページに書いてある内容が微妙だったんで試してみた。

https://nukeygara.atlassian.net/wiki/display/AUG/System+Requirements



方法1.VMWareのお世話になる

GPUが検出できなくて詰んだ。

なんか手を打つことができそうな気はする。



方法2.WineとかNihonsyuとか

http://matome.naver.jp/odai/2140238022377155001


結果

CRhBJKHUAAAEwZ7.png


現時点での結論

Windowsマシンで使おう。


wrote 2015/10/17 20:18:28

Unity on WIndowsで/を使ってるのに\パスが紛れ込む原因がわかった話


概要

Unityが扱おうとするパスは/なのに、\が入ってくるケースを殴りたいみたいな話。

Unity EditorでマルチプラットフォームでうごくAssetとか作ってると、パス周りで以下のような事象にあう。



Unity自体はパスをどう扱おうとしてるのか

Unity自体は、MacでもWinでも(自分は試してないけどLinuxでも) ”/“ を返すメソッドが多々ある。

たとえばAssetのパスを得るメソッドは以下のような感じ。


var data = Application.dataPath;


Windows

C:/somewhere/projectPath/Assets


Mac, Linux(たぶん)

/somewhere/projectPath/Assets

Windowsでも/を使っている。

のだけど、たまに\を返してくる、Unityが面倒をみていないメソッドがある。

今回はそれの話。



\を返してくるのは貴様か

Directory.GetFiles メソッドが、すごく特殊で元気な動きをする。


Directory.GetFiles(path)


ものすごく分岐が多い。次のバリエーションを考えてみる。


1. path = “C:/somewhere/”;

2. path = “C:\somewhere\”;

3. path = “C:/somewhere”;

4. path = “C:\somewhere”;

こいつを、Directory.GetFiles メソッドの引数として使うと、その結果は以下のような感じになる。

1

C:/somewhere/a.txt


2

C:\somewhere.txt


3

C:/somewhere.txt


4

C:\somewhere.txt


3が地獄。

・入力パラメータの末尾が/であれば、/を使う

・入力パラメータの末尾が\であれば、\を使う

・入力パラメータの末尾が/や\でなければプラットフォームに依存したデリミタを使う

という因果関係があるみたい。アホかやめてくれ。



Q. なぜ問題が出るのか

A. Unity内でファイルを扱う場合、高確率でUnityの定義したメソッドを使う。

それらは/を使ったパスを返してくる。

そこに上述のGetFilesとかを使うと問題がでてくる。


不用意に引数に使ったら即問題が出てくるので、なかなかつらい。



Q. そもそも\を使えばいいのでは?

A. Mac,Win.Linuxを跨ぎたいので却下。\を受け入れられるのはWinだけ、しかもUnityも/を使ったパスを返してくる。

たとえば設定ファイルとかに\を使うと、おめでとう、Jenkinsやらなにやらで一切動かないものが出来上がる。

Windowsでの自動化とかを考えても、Jenkinsが/とか使ってた気がするんでおめでとう感が出てくる。


このメソッドを何の確認もせずに使った上で、Path.Combineとかと組み合わせるとさらなる地獄が出来上がる。



対(殺傷方および)策

対策としては、このメソッド使って得たパスを、必ず “\” -> “/“ へと変えてやることで対処する。

なぜだ。残念すぎる。


もうちょっと言及しておくと、recursiveにフォルダ中のものを返してくるメソッドとかはもっとかわいそうな感じで、

全部\で返してくる。


Directory.GetFiles()はこれでもまだマシな方なのだ。


残念すぎる。



wrote 2015/10/01 12:13:37

UnityEditorUndo/Redoシステムについて【解決編】【最新】のコピーそして完結


概要

んっと

これの続き。

http://sassembla.github.io/Public/2015:09:15%2020-56-09/2015:09:15%2020-56-09.html


以下の条件下であれば、ScriptableObjectを自分で用意しないでもUndo/Redoの完璧な追跡ができる感じだった。

1.EditorWindowを使う

2.EditorWindowのインスタンスをUndo/Redoの対象とする

3.Undo/Redoしたいものに [Serializable] か [SerializeField] 句をセットする

4.複数の箇所から参照される要素はどちらかをプリミティブなものにする

実際にAssetGraphの実装でこのUndoの仕組みを使っているが、

無茶苦茶シンプルなコードでうまくいきそう。


順に条件の内容を追っていく。



1.EditorWindowを使う

うん、GUI作るときは使うよね。



2.EditorWindowのインスタンスをUndo/Redoの対象とする

EditorWIndowのインスタンスはUnityが管理してくれてる。

ScriptableObjectのSubClassだけど、フラグ指定してあるので変なタイミングでnullになったりすることは無い。


んで、ScriptableObjectのSubClassなので、Undo.RecordObjectに使用できる。


Undoしたい変化を行う前に、WindowEditor内で、


Undo.RecordObject(this, "Move Tack");


引き続いてUndoしたい変化を書く。

それだけ。


WindowEditorが保持してるListに対してのAddだろうが、RemoveAtだろうが、なんでもなんとかしてくれる。

前の記事で書いてたみたいな自前記録はまったく必要なかった。(どっかミスってて反映されてなかったんだと思う。)


3.Undo/Redoしたいものに [Serializable] か [SerializeField] 句をセットする

EditorWindowのクラスに含まれているものの中で、必要な要素にだけつける。

たとえば 


public List<AutoComponent> autos = new List<AutoComponent>(); 


みたいなのをUndo/Redo可能にしたい場合は、

[SerializeField] public List<AutoComponent> autos = new List<AutoComponent>();


まあ、、当たり前だよな、、みたいな気持ちが出てくるが、SerializeFieldつけるだけで追跡してくれる。

この場合はAutoComponentっていう自作クラスを対象にしているので、AutoComponentクラス内のUndo/Redo対象にしたいものにもSerialize句をセットする簡単なお仕事が出る。

クラス定義箇所にSerializable句、

[Serializable] public class AutoComponent 


あとクラス内の追跡したい項目にはSerializeField句を付ける。

[SerializeField] private bool active;

自分は趣味でprivateとかの前にしてるけど、宣言の真上でももちろん効く。

[SerializeField]をつけたものがさらに内部にパラメータをもっている場合、それらにも、、っていう感じになる。

このあたりの理屈はUnityの中の人が書いてくれてる素晴らしい本があるのでそのへんが大変参考になった。


Editor拡張入門

http://anchan828.github.io/editor-manual/


このへんの属性をつけるにあたって、入れ子になってるのがガンガン続く場合かなり面倒だけど、

そこかしこでScriptableObjectを継承しまくってパラメータありコンストラクタが全く使えないよかメンテコスト的に劇安い。。



4.複数の箇所から参照される要素はどちらかをプリミティブなものにする

文面からだけだとなんのこっちゃと。


たとえばこんな感じの構造があったとする。


EditorWindow 

List<Node> nodes

List<Connection> connections


Nodeはノードウィンドウ一つ一つの型、ConnectionはNodeの間をつなぐ接続線。

img.png


ここで、Connectionの中に特定のNodeへの参照をNode startPoint とかの形で保持、とかやってると、

ConnectionのUndo/Redo時に困る。


たとえば次みたいなコードがある場合だ。


Connection.cs

[SerializeField]Node startPoint;


何が起きるか。


具体的には、いつか、GUI上でNode間にConnectionを追加したあと、Undo -> Redoで再生成されるConnectionの中には、

「Connectionの中のNodeの参照」があり、こいつの存在のせいで動作がややこしいことになる。


値は保っているんだけど、「作り出してしまう」ので、

・上位階層から見たら孤立したNodeインスタンスが一個できる感じになる

・Connection内から見たら、パラメータは全部合ってるんで異変に気付けない


というワンダーランドができてしまう。



なので、出来るだけ相互参照する要素の内容を小さくする、、みたいな原則を守るようにして、


Connectionの中でNodeの参照を保持

Connectionの中でNodeのId(string)を保持

Connection.cs

[SerializeField]string startPointNodeId;


というように変更すると、stringがどう生成されようがNodeのインスタンスが生成されるわけではないので、

問題なくUndo/Redoが発生させられる。


まあそうしとくべきだったねみたいなところがある。idでコントロールしてて本当によかった。設計の勝利だ。


wrote 2015/09/17 3:14:23

UnityEditorUndo/Redoシステムについて【解決編】【最新】


概要

UnityEditorのUndo/Redoを管理するシステムについて、

ScriptableObjectとかを使わないでも後付けで割と楽にUndo管理できるかんじになった。

採点してほしい。


☆この記事に書いてある内容は古くなった。もっともっともっと楽にUndo/Redo実現できた。

以下を見ような。

http://sassembla.github.io/Public/2015:09:17%203-14-23/2015:09:17%203-14-23.html


サンプル

https://github.com/sassembla/UndoSample



ScriptableObjectをEditorで使った場合の欠点

1.以下のタイミングでnullになる

・UnityEditor起動時にInstance作成していた場合、UpdateやOnGUIが2~3回走ったあとにnullになる

・EditorのPlay -> nullになる -> Stop -> nullになる


たとえばEditorWindowを使っていて、そこのOnEnableでScriptableObject派生のインスタンスを初期化した場合、

OnEnableが発生したあと、特定の秒数後にすべてのScriptableObjectがnullになる。

ちなみにこのときOnDestroyとかは発生しない。

なんだかEditorの挙動と連動しているっぽい。


2.生成 -> Undo -> 消える -> Redo -> 復活 の際に、identityを失って困る

下記で詳しく書く



1.ScriptableObjectをEditorで使うとnullになるケースへの対処

たとえばScriptableObjectを避ける

正確には、「ScriptableObjectやその拡張を自分で作成して使う」のを避ける。


EditorWindowのインスタンスなんかはScriptableObjectを拡張して作られているが、こいつらは突然nullになったりしない。

なのでUndo/Redo記録にはEditorWindowのインスタンスを使うといい。



2.復活の際に困るケースの紹介とその解

要約すると、「Undo/Redoするとidentityを失ってRedoで関係再構築ができなくなる」問題。


次のような場合を想定する。


オブジェクトid Aを生成

-> オブジェクトid Bを生成、Bはオブジェクトid Aの下にぶら下がるような関係

-> Undo

-> オブジェクトid Bが消える

-> Undo

-> オブジェクトid Aが消える

-> Redo

-> オブジェクトid Aが復活(この際呼ばれるのはデフォルトコンストラクタ)

出来上がるのはオブジェクトid A’

-> Redo

-> オブジェクトid Bを生成、、、するんだけど、オブジェクトAは存在してなくて、呼ばれちゃうのはデフォルトコンストラクタで、、、

出来上がるのはオブジェクトid B’



オブジェクトid BをRedoしたつもりが、Bの生成にはデフォルトコンストラクタが呼ばれてしまい、

またその要素をセットするのも難しい(ていうかセットする値を覚えているやつが居ない)


「Undo/Redoするとidentityを失ってRedoで関係再構築ができなくなる」


さてどうしよう、っていう。

Undo -> Redoの流れで、非常に困る。

特にリストでものを扱ったりする際に困る。

Undo/Redo対象がScriptableObjectでもScriptableObjectでなくても困る。



Q.なんでこうなってるんだろう?

推測A. 

前提として、MonoBehaviourとかComponentとか、そのへんを扱う前提だからじゃねーかな、、

Componentへの干渉とかも特別にトラックしてるくらいだし。

たとえばGameObjectとかを扱う場合だとすごくスッキリ動くんだけど、Editor側で利用するにはnull化とかがあって正直無理。

んで解


解決を考える。

生成時にフックになるような情報(ここではindexと生成idを組み合わせた辞書)を持っておく。


あるリストがあるとき、その要素は


[0,1,2,3,,,] みたいなindexで表される。


これは要素の途中削除を行わない限り、Undoしたら最大1項目減り、Redoすれば最大1項目増える、という形になる。


こんなリストがあったとして、

[] (empty


このリストに何かを足す(Do

[0]


このリストにさらに何かを足す(Do

[0,1]


このリストに足したのをUndoする

[0]

このリストに足したのをUndoしたのをRedoする

[0,1]


というかんじに、indexの値と動作の内容は完全に一致させて記録することができる。

この関係は増えたり減ったりするのが連続した1次元的な事象である限り崩れない。


要素の途中削除を避ける方法としては、論理削除とかがありえる。(要素からは消さず、ただ見えないことにする等。)

この特性を利用して、

オブジェクトid Aを生成

生成時にint index_of_A(たとえば0)をキー、id値 Aをvalueとして持つ。


-> オブジェクトid Bを生成、Bはオブジェクトid Aの下にぶら下がるような関係

生成時にint index_of_B(ここではAのindexが0なので、0 + 1 = 1)をキー、id値 Bをvalueとして持つ。


-> Undo

-> オブジェクトid Bが消える

-> Undo

-> オブジェクトid Aが消える

このあたりの動作では生成時の記録は干渉されず、消えない。


-> Redo

-> オブジェクトid Aが復活(この際呼ばれるのはデフォルトコンストラクタ)

出来上がるのはオブジェクトid A’


ここで、Redoをトリガーに、A’(indexは0)の内容を、記録をもとに過去存在した A に書き換える。


-> Redo

-> オブジェクトid Bを生成、、、するんだけど、オブジェクトAは存在してなくて、呼ばれちゃうのはデフォルトコンストラクタで、、、

出来上がるのはオブジェクトid B’

ここで、Redoをトリガーに、B’(indexは0)の内容を、記録をもとに過去存在した B に書き換える。


という感じで、コンストラクタの役割を持たせることができる。


「途中のオブジェクトを消してはならない」という制約はつくが、安定して動く。

Undoで消えるぶんには、新しい記録が作られるかRedoされるかの2択しかないので、問題ない。

新しい記録を作った際にはRedo履歴も消えるので。


実際には上記の説明では端折りがあり、もっと厄介なことが起きている。そして自動的に解決される。


あるScriptableObjectの下に、List<Content> contents があった時、


contentsに対してnew Contentを足したりすると、


Undo時にcontentsが一件消え、


Redo時にcontentsの内容すべてが再生成される

(サンプルをUndo/Redoしたりしてみてびっくりしてほしい。)

ドラマチックゥ~~。


ただし、contentsの内容のすべてが再生成される際、その内部のパラメータは「オリジナルがある場合引っ張ってくる」みたいなのが発生しているらしく、

全く問題ない状態を維持する。不思議だ。まあインスタンスの内容をまるっと覚えておいて反映させる、っていう機構なので、さもありなん。


よって、問題にはならない。



Undo/Redoをあとから設置しやすくなる指針

ガチでやらんかぎりそんなにないとは思うが。


・Redoでのリジェネレーション時にできることを明確にしておく

コンストラクタはデフォルトをつかう、とか。

・Inspector表示用にはScriptableObjectが使える(時々勝手にnullになるが)

・Inspector表示用以外にScriptableObjectまたは派生物を扱うのはやめる(スッゲーめんどいので)



まとめ

EditorWindowにUndo/Redoを積んで、new -> Undo -> Redoさえ追跡できるようになればUndo/Redoめっちゃ簡単だぞ!!

私は悟りを開いた。



一巡した世界の果てで「えっそうなの」って叫ぶ

ということで中の方に読んでいただいたところ、


・ScriptableObjectがnullになるのは、ScriptableObject 内で hideFlags = HideFlags.DontSave; とかやるとnullにならなくなるよ


って教えてもらった。


うおーーー素敵。

んで、あとは、


ScriptableObjectをガンガン作る


or 

上位に一個記録媒体みたいな役割を置いて下位を自動的に監視する、の2択。



個人的には上位集約させるほうが枝葉にUndo書くとかがなくなってくれるので好き。

一定の共通の意味の処理を上位に集約できると、挙動変えたり直すの楽なので、、


各ScriptableObjectでRecordObject書くのはヤダなあ、、まあ郷に入っては郷に従え。



そして3週目の世界へ

この記事に書いてある内容は古い。

以下を見て欲しい。

http://sassembla.github.io/Public/2015:09:17%203-14-23/2015:09:17%203-14-23.html

wrote 2015/09/15 20:56:09

Unity データを型指定無しResources非経由で楽に読み込むのを探求する


概要

例えばプラグイン作っていたとして。以下の条件を考えたいとする。

1.Editorで作ったデータ(string)をEditor以外、例えばスマフォ上で動くClientでも使いたい

2.UnityEditor外でもヒューマンリーダブルにしたいのでassetは使いたくない(手、テキストエディタとかでも編集したいしサーバ上でも内容確認したい)

3.Resourcesフォルダ作ってテキストとか置くのヤだ(TextAssetの拒否)

4.通信したくない

5.そのファイルが無くてもコンパイルが通るようにしたい

となるとどんな方法が使えるのか?

最終的には全ての条件を満たすものができた。



コードからScriptableObjectのコードを生成して使用する

ScriptableObjectをInstantiateするのは、Clientからでもできる。


usage:

var scriptableObj = (ScriptableObjectClass)ScriptableObject.CreateInstance("ScriptableObjectClass");



ScriptableObjectClass.js

#pragma strict


class ScriptableObjectClass extends ScriptableObject {

}


サンプルがjsであることに特に意味はない。

usageのような書き方で使用できる。


んで、ScriptableObject のインスタンスから hello というstringを得るコードを考えると、usageとScriptableObjectClass.jsはこんな感じになる。



usage:

var scriptableObj = (ScriptableObjectClass)ScriptableObject.CreateInstance("ScriptableObjectClass");

var result = scriptableObj.GetHello();// = “hello”



ScriptableObjectClass.js

#pragma strict


class ScriptableObjectClass extends ScriptableObject {

public function GetHello () {

return "hello";

}

}


ここまでだと、要件の1~4は満たせる。

1.コンパイルされるコードなので、コードがEditorフォルダ外にさえあればどこからでも使える。

2.所詮テキストなのでヒューマンリーダブル。

3.Resourcesフォルダの世話にはなっていない。

4.通信してない。


が、5が満たせない。

5.そのファイルが無くてもコンパイルが通るようにしたい

usageの中にScriptableObjectを継承したクラス名 ScriptableObjectClass の指定があり、そのせいで「このクラスが存在していないとコンパイルが通らない」。



ファイルが無くてもコンパイルが通るようにしたい

キャストがあるんで型情報が無いとダメ、、って感じなので、とても普通。

partialを使っても同じシグニチャのメソッドは複数定義できないのでダメ。


で、それについて悩んでみたら、よく考えたらScriptableObject、基礎としてToStringメソッド持ってるので、

ToStringメソッドをオーバーライドすると型指定しないでも目的の値を返せていいな~みたいなことに気づいた。


ScriptableObjectClass.js

#pragma strict


class ScriptableObjectClass extends ScriptableObject {

public function ToString () {

return "そして殺す";

}

}

で、この書き方をすると、usageから型のキャストが消せるので、

その型が存在して無くてもコンパイルが通るようになる。


usage:

var scriptableObj = ScriptableObject.CreateInstance("ScriptableObjectClass”);// キャスト消えたな。つまりその型のファイルが無くてもコンパイル通る。

var result = scriptableObj.ToString();// = “そして殺す”


感想

5.そのファイルが無くてもコンパイル通る、のせいでいろいろ面倒な感じ。

そのファイルがなかった場合はエラー、というフローが本来は必要。実際の対応はアサーションとかで殴るとかか。

後から読むとヒントがCreateInstanceメソッドの引数くらいしかないのも減点ポイント。(まあ十分だとは思うけど。)


データソースとしてのヒューマンリーダブルさを求めつつResourcesを拒否するとこうなった。

ひどいことになってると思うので別解を求む。


とおもったら、ScriptableObjectを継承したクラスをでっち上げて、そっちは常にある、みたいな構造がつくれればいいな。

wrote 2015/09/08 18:33:34

ぬる舗渋谷 もくもくうどん会 晩夏


概要

もくもくしながらうどん食べたりします。

https://chouseisan.com/s?h=8a778e0c9929491fb61d67bf28888244



場所と時間

ぬる舗渋谷

https://www.google.co.jp/maps/place/〒150-0032+Tōkyō-to,+Shibuya-ku,+Uguisudanichō,+15-10+ロイヤルパレス渋谷/data=!4m2!3m1!1s0x60188b50a2940c75:0xba0c9076fff11b10?sa=X&ved=0CB0Q8gEwAGoVChMIit-Km-7QxwIVQ-imCh3qjA4z


202号


9/6(日) 11:00~ まあ適当なタイミングでくるといいと思います



やること

適当にもくもくしたりしながらぬる舗製麺所のうどんとか食べ続けます。


参加時間とかは適当で。主な話題はゲーム作りだったりクライアント側だったりサーバ側だったり。うどんだったり。

なんかディスカッションとかメモしやすいように壁にホワイトボードつくったりできるようにしときます。たぶん。

ホワイトボードのある酒場感。


冷やしうどんとかをメインに出すつもりですがぶっちゃけ足りなくなれば製麺したりするので自由です。

あと晩夏だから暑いんじゃないかと思って用意してるけど寒かったらあったかいうどん食べたいな?

あとイレギュラーですが映画ながしっぱなしとかしようと思ってます。

皆さんからのあたたかいダメな映画持ち込み期待してます。詳しくは下記



Enable

会場では以下のことができます

・PCとかマシンと材料と飲料持込

・おかず作り

・食べる

・飲む

・書く

・無限インタネット

・給電

・出前(スッシとかピザとか

・倒れる



Disable

・石油王はありません

・V8



最後に:映画について

ぬる舗では有事の際、次のような映画を流すことを強く推奨しています。

クソ映画祭情報(2013~2014年越し版レギュレーション)


概要

クソ映画祭とは

2013~2014, 2014~2015の年越しに行われた酷い事件。

年越しの瞬間まで各自が持ち寄った思い出の「酷い映画」を流し続け、基本的に年越しの思い出を汚します。


酷さの方向は人それぞれですが、レギュレーションや過去の上映作などから傾向が見えると思います。

映画は各自の持ち寄りに依存します。



レギュレーション

以下のレギュレーションをもうけようと思います。


・アドレナリンみたいな「あーーうーーんこれはひどいある意味で、、良い意味でもなんだけど人にオススメしにくい」映画を集めよう。

そんなアドレナリン

http://bit.ly/1fP105G


・別に誰もみてない瞬間があってももちろんOK、クソ映画だからな!

・18禁はメンツ的にはありだけどうーんエロメインだと引く。

・再生できるメディアはDVD、ブルーレイ、ウェブ上。

・海賊版ディスクは寂しいのでやめよう。買ったりして自分が金を使ったっていう痛みがあるやつが一番良いと思う。

・1本の上映時間は最大を3時間くらいにしようと思う。

・ドクターストップ、メシストップありです。

・早送りとかは禁止しない。

・直前でノミネートを見直すのアリ。



過去のアレ(一部)

ロボット(https://www.youtube.com/watch?v=GBuxFbgzJG0)

ブルース・ブラザーズ(http://amzn.to/1EtsnOK)

リンカーンvsゾンビ(http://amzn.to/1UeYrN7)

ゴスロリ処刑人(http://amzn.to/1JpZW0B)

バトル・オブ・アトランティス(http://amzn.to/1NPIbxh)


IMG_0545.JPG

wrote 2015/09/06 11:10:00

CEDEC2015 Day3 メモとか


概要

メモ



物理ベース時代のライトマップベイク奮闘記

シリコンスタジオの方。



ライトマップの効果

最終出力時まで一貫して効果的。


ワークフローの構築

3ds Max + V-Ray

メンタルレイのノイズが気に入らなかったり時間かかったりなのでV-Ray


これ資料アップされるの待ち遠しいな

生成時のいろんなツールのつぎはぎパイプラインすごくつらそう



正しいライトマップ

V-Rayは物理ベースレンダリング

ライトマップに書き込まれるべき値

GrobalIllumination

間接光による値

間接光による照度


あとDirectionalLightの成分とか見てみて云々



クオリティ

ノイズの低減



ライトマップが適応されているものといないものを明確に分けられている

たとえばロボとかのディフューズはライトマップのデータから引っ張られている(?)



質問してみた

どんな言語とかでツールチェーン組めたら幸せな感じがありますか?

->なんでも。一貫して安定してれば。

なるほど



IoT向け汎用protocol MQTTのリアルタイムゲーム通信利用と実装、そして未来へ…


崖っぷちバスターズでの事例

技術採用プロセスとか。



IoTとは

はい



ネットワークゲームのはなし

2010年代のネットワークゲーム

高速なインタネット

MO/MMO

eSports

スマフォ

常時接続前提のゲームあるよね


環境

3/4G

最低で2MB/sとか


崖っぷちバスターズ事例

シングルプレイ

マルチプレイ


シングルプレイだとWebAPI

マルチプレイ

バトル部分はリアルタイム、4人


Bisqueっていう開発基盤をつかっている

Cocos2Dとかをベースにクロスプラットフォームな


前提としての会社の強み、弱み

Web APIは得意

クラウド利用実績とか


リアルタイムサーバ、クライアントとかの構築はやったことない


目指したこと

・実装スピード重視

・1Room 4player ターン制

・レイテンシ最大1秒


プロトタイプの結果、

クライアントにHostをたて、サーバはメッセージのpub/subに徹するタイプになったぽい


比較検討したもの

polling

WS

Socket.io

MQTT

Platform機能(iOSのやつとか

商用エンジン


インフラ、クライアント、ゲーム性の観点からMQTTを選択


(ここでの)MQTTとは

pub/sub

低速、不安定なネットワークでも動く

軽量

QoSあったり


MQTTの解説

はい



実装について

全体像


MQTTBrokerServerをBattleInstanceServerとして利用

Topic -> Room

Room管理はAPIServer制御

マルチプレイバトル

WebAPIでマッチング

マッチング情報をBrokerServer(BattleInstanceServer)へと転送


Clientの一人がHostになり、SessionMasterとして同期移譲管理


broker

room


c1 c2 c3

(Host)


送信するデータはクライアント側で暗号化してる。


(これクライアント側正当性みたいなのクライアント自発的なやつなので、チートしやすそうだな~~~

暗号化してようが暗号化ロジックはクライアントの中にあってクライアント開ければ暗号化手段はそのまま利用できるんで、

この部分の意味はネットワークとかプロキシとかでの中間変更不可という要素に収まるんじゃなかろうか。

んでクライアントから出たデータをそのままpub/subしちゃうので、

データの正当性判断要因や拒否機構がどこにも無く、かつクライアント群という全員クライアント状態なので、運営がチートに気づけるチャンスがなさそうな気がする、、


もうちょい詳しく書くと、全員クライアントで神視点的なバリデータとか状態変化監視者が不在なので、

誰がどんなデータを出しても、受け取る側はとりあえず正しいと思うしか無くて受け取っちゃう、みたいなところがある。

なんだけどこのゲームの場合必殺技のコスト無視とかそのへんで出そうなくらいで

チートされた場合のダメージと比較して看過してるのかな


守りたいのが公平さなのか自作のシステム堅牢性なのかみたいな話で、

ぶっちゃけひどい目にあうユーザが居ない(PVP要素がない、協力プレイで味方が強い分には問題ない)のであれば、

暗号化でシステム堅牢性に目を向けるだけっていうのはメッチャ健全で良いなあと思った。

)


余談

PhotonがClient-ClientRPCとかをサポートしてて使うのすごく楽なんだけど、あれ使ってクライアント群内にHost作るとかそういう感じに進むと

PvPとかがあるゲームルールによってはチート情報を全クライアントで無条件にSyncしちゃってそれを誰もValidateできずに

最高にキッツイ状態になるので、何事もまずは選択肢増やして使う際に気をつけるべきだなあという感想。


簡単にそういうのできるソリューションを選べると良いな。

Hostが落ちた場合は別のClientに移譲する

これ地味にめっちゃ大変なはず、誰がNext Hostなのかを判断する要素がサーバ側に無いと楽にならないような、、

WebAPI側で解決してたりするのかな。もしかしたらそうおっしゃっていたかもしれない。

質問で聞いてみたかった。

BrokerServerの実装は?

一台あたりの性能、コストを最大化したい

高負荷時の安定性 あたりを基準に見ている


MosquittoとRabbitMQ with MQTT Plugin が候補に残った

Mosquitto

シングルスレッド、クラスタリングする場合は自作


RabbitMQ

マルチスレッド、クラスタリングあり <- RabbitMQを選択。


構成案

Broker Standalone parallel


結局パフォーマンス劣化、接続時間のトレードオフなどからクラスタリングせず。


AWSでのオートスケーリングが効く環境を構築して云々


アプリケーション編

クライアントライブラリの実装の話

選定

フルスクラッチ or paho or Mosquitto

ライブラリで使えればいいよねって感じでMosquitto(libmosquitto)を選択。


BSDソケット使ってるんだけどiOS/Androidでいろいろ問題が。

→Mosquittoのコードには手を加えないでいいように工夫(Define置き換えとか)



トピック一覧

Common

ブロードキャスト

System

ブロードキャスト


Host

相互死活判定

ゲストが投げるとHostに集約される


Private/ゲストID

ホストがゲストに対して送付

お互いに送れば擬似P2P


QoS

アニメーション情報とかはQoS0

衝突、必殺技などの必須情報はQoS1


最悪でもQoS1のもののみが届けばゲームが成立するのを想定して振り分けている。

QoS1で送っているものについてはさらに再送をする機構をつけた(?)

これどこでコントロールしてるんだろう。サマーレッスンの時間迫ってたので部屋でちゃった。



データ構造

msgpack



今後はpahoに乗せ換える予定

あとElixirとか試し中



サマーレッスン

整理券失くすとか凄まじいダメさを発揮しつついろいろあって復帰して観れた。 感謝しかない。。

箇条書きで

・人と対面する、っていうシーンなんだけど、これ火力あげるには他人の中の自分、みたいなのの表現が必要で、「これスペックとか表現で突破できるものなのかなあ、、超優秀な表現AI、そのグラフィック表現が必要な世界でメッチャ遠そう」みたいな感想。

・臨場感を感じさせるための工夫みたいなのはなんかしっくりこなかった。

・画質はCBのほうがよかったな~と思いつつ。

・ユーザーが何かをしたい、っていうのを引き出す系統ばっかり触ってきたので、そういうタイプじゃないコンテンツだなと思った。PS3の「アフリカ」とかをちょっと思い出す。

自分は「綺麗」っていうパラメータが何かを触る時のモチベーションとして長時間もたないタイプなので、なんか綺麗なだけだとつまらないんだなと思った。

このへんは女子高生のお部屋モードだったら俺の感想は違ったんだろうか。あんま違わない気がする。


VR、「許されるツッコミやすい隙」みたいなのがあれば、想像力の余地の世界、みたいなのがまた発生しそうな予感がある。

wrote 2015/08/28 13:35:55

Unityのエディタ拡張でのメチャ細Tips


概要

他に書くところがなかった。



方向キーを使って入力するときのBeep音を消したい

自作のエディタでも方向キー使いたいじゃないか~~

んで単にInput.GetKey とかやってたらBeep鳴るわけ。

Event.currentとかから取得しても鳴るわけ。


Eventから取得するようにして、Event.current.Use();としたら無事Beepしなくなった。



任意の範囲をスクロールすべき空間としてスクロールバーに認識させる

スクロールバーに対して、適当な広さのスクロール範囲を与えてスクロールできるようにしたい、、

ただし中身が敷き詰められてるわけじゃない、、


みたいなケースの時に使える方法。


// スクロール値保持のためのユーザー定義値、どっか適当なところに定義

Vector2 scrollPos = Vector2.zero;


// スクロール範囲開始

scrollPos = EditorGUILayout.BeginScrollView(scrollPos);


{

// このへんにスクロール対象のコンテンツ

}


// サイズ指定のRectをGetRectで生成(これで1000 x 500のスクロール範囲)

GUILayoutUtility.GetRect(new GUIContent(string.Empty), GUIStyle.none, GUILayout.Width(1000), GUILayout.Height(500));


// スクロール範囲閉じる

EditorGUILayout.EndScrollView();


特定のサイズの領域を、スクロール可能領域としてUnityに信じ込ませることができる。

っていうかなんなんだこのUsageは、、


書くところなかったら随時追加してく。

wrote 2015/08/27 21:54:57

CEDEC2015 Day2 メモとか


概要

メモ



GPGPUを活用した剛体シミュレーション最適化事例


GPUが得意なこと

特殊効果的なやつ

物量で賑やかな画面を演出する


精度はそこそこなんだけど大量。



拘束ソルバーって何

衝突検出、反発力計算、移動

Collision Detection, Constraint Solver, Integration


これのConstraint Solverのところ。


A,B,Cの三つの物体がぶつかる時、A-B,B-C,C-A間で、全ての物体同士が貫通しない、というような三つの拘束に対しての解が欲しい

ヤコビ法ガウズザイデル法とかで解ける。ただし不等式がふくまれるので、一意にならない。ので、反復解法というのを使う


解決条件を満たしている解λを0~無限の範囲でクランプ(保持?)

0に近い値を望む。

拘束式

CEDEC 2008 物理エンジンの作り方

というのがあるのでみよう。

ヤコビアン:変換マトリクス。速度を拘束軸上に変換する。

拘束軸上?:衝突ポイント上に存在するベクトルみたいなものぽい


式の名前かな


ガウスザイデル法を高速に解く

A-B

B-C

A - C

C-D


同じ剛体を共有しないものは個別に計算できる。


で。


ヤコビ法について、

並列にできる部分を上記のようにみなす方法をつかってみたところ、あんまりよくなかった。

・並列性の悪化

・並列化のためのコストがあった。。


なんで?

計算内容とその反映タイミングの問題。

・ガウズザイデル法だと結果が収束する

・ヤコビ法だと結果が発散する


なので、

・ペア同士の計算はザイデル

・ペア全体の計算はヤコビ

と振ることで、計算量の削減をはかりつつ、、みたいな話


ヤコビ法について

SOR

SUR

SURを適応するとデルタが小さくなって解が発散しにくくなる(解が定まりやすくなる


Weightみたいなパラメータを追加してSURとして適応する

出し方いろいろ。とりあえずインデクシングしまくるみたいなかんじ。


Biasの追加

めりこんだぶんを速度に加える。

貫通してる方向と深さに対して反発力を追加する、みたいな話


反復回数少なくてもいいかんじに動く、みたいなのが目標。


結論

・ガウスザイデル法より修正を加えたヤコビ速くて軽い

・物量が増えてくるとだんだん同じような結果を出す感じになる

・ただ量が増えてくるとメモリアクセスやらで減速する



メモリアクセス周り

流体、粒子ベースシミュレーションで得られた知見

メモリアクセスの効率化


データ構造の変換による効率改善

Array of struct

Struct of array


AOS:

{

pos

vel

}


SOR:

{

pos[N]

vel[N]

}


SOAのほうがキャッシュヒット率良いよ(無駄なデータを読まないので


空間充填曲線をつかってメモリアクセス局在性の最適化

「もし座標上近い物体が隣接したメモリポイントに存在すれば、キャッシュヒット改善するんじゃね?」


テクスチャのピクセル配置に対して、

swizzle化という処理を行うことで、テクスチャ座標上で近いテクスチャのポインタがそれぞれ隣接するといいなみたいな。


空間充填曲線

Z曲線

ヒルベルト曲線とか


「スクリーン座標上でも近いピクセルは、テクスチャ上でも近い、みたいな法則を利用する。」


モートンコード

・低コストで扱える空間充填曲線


メモリをソートした結果、3~4倍の高速化

ソートにかかる処理の重さに比べて圧倒的に高速化のメリットが出る


なるほどな~~


モートンコードのコードはなんかサンプル見よう。

hash gridとも相性がいい



ありあまる演算資源をどのように使い切るか

そうだAsyncShader使おうみたいな話



サブディビジョンサーフェスのすべてがわかる・グラフィックスエンジニア向け理論編


資料発表が発表終了直後だったのでありがたくよみかえしている。

http://takahito-tejima.github.io


wrote 2015/08/27 14:50:47

CEDEC2015 Day1 メモとか


概要

私的な物でローカルに保存しとくと参照するの面倒なのでという感じ


ニコ動


お手本の発明

「クラスの人気者」「有名人」になりたい、ではなく、

やってみたい、という欲求を叶える

みたいな話



一つのコンテンツに対していろんなひとが真似る

いろんな方法で真似る

という「遊び」なのではないか


共感の連鎖ができることが「ネットでの遊び」みたいな



シドニア


プリプロダクション

シリーズ構成、ストーリーボードとかお話とか、ストーリーリールまで

プレスコでやってる


声データを元に時間関係をもつことができるので、ツール上で並べて時間を計る、みたいなのが楽にできて良い。


スーツのモデルとか、上にゴテゴテとものをくっつけることで別物に見える、みたいなことを考えてある。

省力化とか。なるほど。


アニマティクス(って何)で出撃シーンを作ってみる

滑走路を飛び出すところ、照り返しとかカメラワークの効果の検証とかをやってる。

ストーリーボードとかだけだったらここまで凝ることができなかった。

ここはコンテありきじゃないんだなあ。


巨大感

空気遠近あったほうがいいなってなったので空気(みたいなもの)があることにした。


プロダクション

キャラクターデザインに関する話

理想っぽい絵を出す時、萌え絵っぽいところと原作準拠のところを両方押さえて、モーフィングでバランスを探った。


アイポイントの話

光彩もモデリングしてあって、横を向いた時とかに凹凸がみえるようにしてある。

まつげ、二重まぶたはジオメトリで制作されている


ディスプレースメントをトゥーンシェーディングにあっても使ってる



フェイシャル

ふくわらいっぽいコントローラ作った

パラメータで個々のパーツ動かしたり。表情筋だけだとトゥーンシェーディングでの表現幅が狭くて辛いみたいな感じで。


ルックデブ

見た目の場面内で自動的に行われる調整

フレネル入れたりバンプ入れたりして、


メンタルレイを使っているが、表現の幅が足りないと感じたのでチューニングとか

ボックスに対して球体のノーマルを適応、パラメータで調整可能に


影のアルファを調整することで、例えば「距離を考えると影が薄くなる=遠い」みたいな感じで、影に距離依存のグラデーションをかけるようにして巨大感を表現


画面内のサイズによって輪郭線の太さを変更

カメラからの距離だけだとズームの時に問題になるんで、っていう。


リップシンクについて

ツール作ってキーフレームが自動で振られる。拍の解像度については2Dアニメの常識を適応みたいな話なのかな

エフェクト

MayaのLiquidとかHoudiniのなにか、あとヌーク?

作品内で、たとえば顔に落ちる影の形でこんなのがGoodこんなのがBadみたいなのコレクションしてある

こういう影Goodだよねっていう感じ


最終的にコンポジットでタッチ、プロジェクションマッピング

表情についての調整などを、Geometry名などから引けるような形でコンポジット時に発揮できる形にしてある



編集

フィニッシング

ここまで揺れとかのエフェクトをつけてはいない。

スモークとかエフェクトをかけるみたいな。



パイプラインを継続的にバージョンアップさせてる


・ずっと昔からやってる

・大規模プロジェクトを海外と組んで開発する時に完全に作り直ししてる(2.0

・今は3系作ってる

具体的には何?(2.0の話


グローバルパイプライン

すべてのスタジオで同じワークフロー、ツールを共有

スタジオ間でデータ共有/ツール共有を自動化(これほんとすごいな、他の物事の基礎になってる。

ステータスや進捗状況の一元管理と見える化

レビューのシステム化

PPIツールズっていうツール作ってる

ツールランチャー

ツール起動する基盤


ディレクトリマネージャ

共通のフォルダ階層とネーミングルール持たせることができるやつ



パイプラインに関わるデータはすべて入出力の経路が決まってる

ほんとにすげえな


スタジオ間でのデータ転送

バッチではなくリアルタイム、UDPでぶっとばすレベル

日本は主にアニメーションつける前までの工程をやってる、そっから先は各国

なるほどな


CBよかった

wrote 2015/08/26 14:13:47

UnityEditorでScriptableObjectをListに仕舞うと楽しいがUndo対応でハマった【後、よくした】


概要

ScriptableObjectをList内に突っ込んだ場合の挙動とUndo、Redoの組み合わせがキッツイ状態を作り出す。

最小構成作ってみて遊んでみよう、と思ってハマった。


成果物がこれ。

UndoSample

https://github.com/sassembla/UndoSample



要素

ScriptableObjectを適当なScriptからCreate、Listに仕舞った場合と、そうでない場合の挙動の差があってハマった。


・ControllerScriptからScriptableObjectをCreate、初期値をセット

・Registerにその内容をセット、Undo/Redoを可能にする

・UndoでScriptableObjectが消える

・RedoでScriptableObjectが復活する


のだけど、


例えばControllerScript側で次のようなコードを書いていたとする。



ControlScript.cs

List<RecordObject> contents;


private void CreateContents () {

contents = new List<RecordObject>();


{

var newRecord = ScriptableObject.CreateInstance<RecordObject>();

newRecord.data = 100;

Undo.RegisterCreatedObjectUndo(newRecord, "Create RecordObject:" + newRecord.GetInstanceID());

contents.Add(newRecord);

}

}


CreateContentsメソッドが呼ばれたタイミングで、

・RecordObjectのリストを作成して新規作成

・作成したRecordObjectのdataパラメータに100をセット

・UndoスタックにCreateしたことを記録

・RecordObjectをcontentsに追加


んで、対象となるScriptableObjectを継承したRecordObjectはこんな感じ。



RecordObject.cs

public class RecordObject : ScriptableObject {

public int data;

}


で、Undo(command + Z)を行うとどうなるか。

作成されたRecordObjectは破棄される。

OnDisabledとかメソッドを持っていたらしっかりと呼ばれる。


RecordObject.cs

public class RecordObject : ScriptableObject {

public int data;


private void OnDisable () {

data = 1;

}

}


例えば data を 1 にする、とかやれば、この場でdataが1になったあとにDisableされる。はず。


で、ここで、List<RecordObject> contents に入っているオブジェクトはどうなるのか?っていうと、

影響を受けない。

nullにならない。

勿論dataは1にならない。

DisableされたあとDestroyされてるのでnullになるのでは? と思ったのだが、Listに直接入れた場合はそうはならない。

ちなみにListに入れずに、インスタンスを一枚噛ませて保持しようとすると、その場合ScriptableObjectがUndo = Destroy後にnullになった。


そのケースはListのケースの説明が終わってから書く。


Listに直接入っているScriptableObjectは大元がUndoで消されたとしても影響を受けない

Destroyしても元気に活動を続ける ControlScript.cs の List<RecordObject> contents 内のScriptableObject。

例えば ScriptableObject .GetInstanceID メソッドを実行しても、nullではないので元気にIDを返してくる。


そこで、Redoするとどうなるのか?


ScriptableObjectのCreateのUndo -> Redoは、ちゃんとScriptableObjectのIDもRedoしてくれる。

つまりUndoで消したScriptableObjectと同じInstanceIDが、Redoで作り出されたScriptableObjectにも振られる、と。


Create from ScriptController -> この時のInstanceIDが-100

Undo -> 消える

Redo -> InstanceIDが-100で戻る


ところで、手元に残っているListにも、、なんだ、、まだ元気な、、nullになってないScriptableObjectのインスタンスがあってさ、、、

同じID -100 を返してきたりする。 うーん。


Listに突っ込むことで参照が消えなくなってるみたいなのがあるのかなあ。

とりあえずScriptableObjectはひたすらいろいろ書く羽目になって辛いのでできるだけ特定の用途以外の内容を書かない方向で済ませたい。


でこれでListに直接入ってるケースは終了。


んで、



Listに入れず、所持オブジェクトを適当に一個作ってそれを管理する場合

以下のような構成にすると、ScriptableObjectは、すべての箇所で、Undoのタイミングできちんとnullになる。



ControlScript.cs

List<Content> contents;


private void CreateContents () {

contents = new List<Content>();

contents.Add(new Content());

}


contentsは変わらずListなんだけど中身が下記。


Content.cs

public class Content {

public readonly string contentId;


public readonly int recordObjId;

public RecordObject recordObj;


RecordObjectを持ったインスタンス。

とすると、


List<RecordObject> contents  -> List<Content> contents に変わっただけ、、に見えるんだけど、

ScriptableObjectであるRecordObject recordObj  がUndoでnullになるタイミングで、

Contentの保持しているrecordObjもnullになる。


Listに直接入ってるScriptableObjectは影響を受けないのに、

Listに入ってるContentが保持してるScriptableObjectは影響を受けることができる。


ああややこしい。

Listに直接ScriptableObjectしまうとなんかなるのはもうなんだ、そんなことしねーよバーーカ!!みたいな気持ちで見なかったことにした。


おかげで都合のいいUndo/Redoを実装することができた。

ここであげたコードを含むリポジトリを下記に用意した。

UndoSample

https://github.com/sassembla/UndoSample



追記

ScriptableObjectでUndo/Redo管理するのいいよね?って思いつつ、「この辺きもいな」って疑念が消えなかったんだが、

考え直して綺麗にすることができた。


re-考え方

ScriptableObjectをRecordとして分散して持っていたのだが、よう考えたら「上位に一個だけ持って内容をRecord可能にすればいいのでは?」という気持ちになった。

で、


・ScriptableObjectをWindowのOnEnableで作る

・その下に全データを構築する

・Recordしたい要素だけSerializeFieldをつける

という手で行けた。


こうすることで、上位の一つのRecordだけをUndo/Redo対象にセットできる。

んで、問題として残るのは、

・new -> Undo -> newしたのが消える -> Redo -> newされて消されてたやつがnewされるがその際にはデフォルトのコンストラクタが使われる

というあたり。


これに関しては Undo.undoRedoPerformed で対象の監視とかをやってRedo後になんとかする、みたいな感じ。

汚い。


あと、依然としてScriptableObjectがUnityEditorのコンテキスト仕切り直しタイミングで影響を受けてnullになることがあるので、相変わらずそのへんだけ対処する必要がある。まあはい。


wrote 2015/08/23 20:47:41

nginx-luaなんちゃらのuuid直した


概要

ほぼ私信。

利用していたuuid作成のためのライブラリが時間単位でしかidを作り出せない構造だったくせに、

os.time()っていうミリ秒のデータではないのを使ってたので、せめて、、、ってことでミリ秒単位に改修した。

あとサンプルというかテストベッドとしてまともな見た目にしてみた。

READMEの内容も更新。やったね!


nginx-luajit-websocket-pubsuber

https://github.com/sassembla/nginx-luajit-websocket-pubsuber



gameContext.html

サーバ側の実装を起動する。gameContextという名で呼んでいるけど、ようは全Clientから接続される先。

スクリーンショット 2015-08-06 19.31.41.png



client.html

開くとclientとして機能する。

メッセージ送ったり、gameContextからのpublishを受け付けることができる。

スクリーンショット 2015-08-06 19.31.35.png



いやあ、手軽。

wrote 2015/08/06 19:30:09

UnityEditorで独自GUI要素をクリックしたらInspectorに出るやつ


概要

できるだろ~と思ってたらできた。

これでScriptableObjectを頑張って拡張しないでもGUIつくれるね。


Repo

これ

https://github.com/sassembla/CustomInspectorWithGUI



wrote 2015/07/29 15:09:18

うどんツアーズ夏の陣ふろく、好きな店一覧の一部


概要

好きなうどんやさん集めた。

土、日、月の3日あればどこかのタイミングで必ず空いているお店だけになった。

経験則的に日曜定休と火曜定休が多いので月曜日をうまく使うとV8できる。



拠点にすると良いと思うところ

高松駅と善通寺駅あたり。といってもそこからうどんやさんは十分に遠い。



以下好きな店



うどんいっぷく

香川県高松市国分寺町新居169-1


いりこだと思うんだけどツユがおかしいくらいうまい。


ひたすら混んでいるけど回転もとても早い。

自分が細麺しか量産できない身の上なので、ぜひ盗みたいワザマエ。



宮川製麺所

香川県善通寺市中村町1-1-20


行った中でいちばんわけわかんない場所にあった。うまい。


最寄りの善通寺駅から1.6km。

閑静な住宅街のど真ん中にある製麺所で、

麺茹でて器に盛って卵かけてツユかけていただきます!

ってやったら次の瞬間器が空になってた。

多幸感だけが残った。麺がひたすらうまかった印象。形容詞がない。

朝8時から開いてるけど8時にあそこにいくのは無理。



うどんバカ一代

香川県高松市多賀町1丁目6-7

釜バターうどんが美味い。火力がある。


長田 in 香の香

香川県善通寺市金蔵寺町1180

バンドっぽい名前。うまい。


でかいひょうたんを渡され、入ってる熱々のツユを小鉢みたいな器に入れて麺が茹で上がってくるのを待つ。

えらい芳醇なそのツユに茹でたてのうどんをつけて食べる。

茹でたてのうどんのもちもちした食感と、いりこの風味が強烈なツユがとてもよく合う。

暴力的なくらいに。


ここの、お湯張ったままの器で麺を出すスタイルは参考になりそう。

何かの。うどん会とか。



山下うどん

香川県善通寺市与北町1017

どこからも遠い。うまい。


かなりコシが強いうどん。

コシの強さは随一。



以下いつか行ってみたい


讃岐屋 雅次郎(大阪)

http://tabelog.com/osaka/A2707/A270705/27019261/



宮武

http://tabelog.com/kagawa/A3701/A370101/37005339/dtlrvwlst/



以下番外


麺処 綿谷

香川県丸亀市北平山町2-6-18


朝8時45分からやってる貴重なお店。

宮川製麺所とおなじ善通寺市内だが、こちらはまだまだまだ最寄りの丸亀駅から近い。

甘目のツユにコシがほんのりあるうどん。肉ぶっかけが安くて美味しい。

食堂っぽい。



ほか

wrote 2015/07/26 22:48:31

関数型Scalaいってきた


概要

これ

http://connpass.com/event/16052/

歌舞伎座近辺お寿司おいしいの良いよね


適当につまみ食いした結果。



とても丁寧な型クラスの使い方紹介

halcat0x15a さんのわかりやし~解説。

http://halcat0x15a.github.io/slide/functional_scala/



PropertyBasedTestingの話

xuwei-k さんがScalazのために作ったテストツールと関連するトピックの論文の話

http://xuwei-k.github.io/slides/scalaprops


Composable Callbacks & Listeners

OE_uiaさんによるComposableなハンドラの話。

http://www.slideshare.net/oeuia/composable-callbacks-listeners


自分はもうJavaとかでAndroid上でのScalaに触ることはほぼほぼ無い(Unityとかそのへん使う)ので、 なるほどこう書くのかあ、みたいな感じで面白かった。

wrote 2015/07/25 13:27:09

逆引きZBrush


概要

学んだ内容が溜まってきたので書く。

あいうえお順とかの並び替えは今後やる。


Version 4R7 P3 (64-bit) (473.64) Mac OS X



Editモードに入るには

Toolをどれか一つでもカンバスに置くとEditモードにできる。

置かないとできない。



左右対称の編集をするには

Xキー or Transform > Active Symmetry

スクリーンショット 2015-07-24 23.54.29.png



カンバスにToolを置くには

Tool > CurrentTool(左上のやつ)に何が選ばれているか確認、

スクリーンショット 2015-07-21 18.19.09.png

例えばポリゴン板を置きたければPlane3Dを選ぶ。

スクリーンショット 2015-07-21 23.04.15.png


選んだ後にカンバス上をドラッグするとToolが置ける。

ここからEditモードに移行できる。



カンバスに表示された残像を消すには

Layer > Clearボタンで消せる

スクリーンショット 2015-07-21 22.56.08.png



すべてのツールを表示、かつ今選んでいるツールだけを編集したい

Transform > Transp をオンにする

+

Transform > Ghost をオフにする。

スクリーンショット 2015-07-21 22.58.06.png

これで、いろいろなツールを見ながら、選んだツールだけを編集可能になる。



アクティブなSubToolを切り替える

上下キーで切り替わる。



SubToolの一覧を表示する

nキーで、「現在ActiveなSubTool以外の一覧」が表示できる


複数のサブパレットを開きっぱなしにする

Preferences > Interface > Palletes > One Open SubPallete



設定を保存する

Reference > Config > StoreConfig



ZSphereをポリゴンに変える

1.Tool > Adaptive Skin > Make Adaptive Skin

2.この時点で作成されたスキンがQuickPickや3DMeshesの中に追加されている

3.Tool > SubTool > Insert で読み込んで使う

4.元になったZSphereは自動的に何か変わることはないので、消したりとか。



ZSphereの一部を消す

altキーを押しながらZSphereの中心をクリックする。

最初の一個のSphereは消えない。



LightBoxを消す

,キーで消える



ツールの色を変える

Color > FillObject で色を一括で変えられる。

color.png



ブラシサイズをズーム具合と連動させる

Draw Sizeの右上のDynamicマークをShift + クリックする。

これで、ズーム具合とブラシサイズが連動するようになる。



Maskモードで使用するブラシを変更する

controlキーを押したまま、ブラシパレットからブラシを切り替える。



現在アクティブなツールのみに影響を与える

Transparencyモードをオンにすると、現在アクティブなツール以外をクリックしても反応しなくなる。


マスクの範囲を細かく表示する

Tool > SubTool で筆のマークをクリックすると、マスクの範囲がグラデーションで表示されるようになる。

スクリーンショット 2015-08-16 20.40.09.png



ハイポリモデルに滑らかな選択範囲をセットする

低Devideを選択してローポリ状態にし、選択範囲をセットしてから高Devide状態に戻すと、

境界範囲が滑らかになる。



マスク範囲を大きくしたい

Tool > Masking > BlurMask

マスクされた範囲に対して、影響範囲を広く浅くする


Tool > Masking > GrowMask

マスクされた範囲を拡大させる



マスク範囲を小さくしたい

Tool > Masking > ShrinkMask

マスクされた範囲を小さくする



ZSphereを一個ずつ動かす

ブラシサイズを1pxにするとかやると楽。



SubToolにZSphereを足す

Tool > SubTool > Append > ZSphere



ツールを合体させる

Tool > SubTool > Merge > MergeDown

まだ試してない



左右片方だけのパーツを左右対称に複製する

1.Tool > Geometry > Mirror And Weld のボタン上でどの軸に対象にコピーするか選択

2.ボタン押して実行



複数のツールを一つのツールに合体させる

1.混ぜたいツールをSubToolパレット上で上、下隣り合わせに並べて、

2.上のツールを選択した状態で

3.Tool > SubTool > Merge > Merge Down



ポリゴンのポイントを動かしたい

Move ブラシを使うと楽



ツールの上にペイントする

zadd, zsubをオフ

rgbをオン

この状態でモデルの上でstandardブラシを動かすと描画できる。



ツールの特定の部分を消す

いろいろな方法がある。


bool演算を使ってツールの特定の部分を消す

Modify Topologyを使ってツールの特定の部分を消す

Trim系のブラシを使ってツールの特定の部分を消す


Trim系のブラシを使ってツールの特定の部分を消す

(要チェック)

TrimRectとか。

Subdivision Freezeが必要。ぶっちゃけDel LowerしてSubdivision消してからReconstructしたほうがいいかも。試そう。



消したSubdivisionを復活させる

Tool > Geometry > Reconstruct Subdiv



bool演算を使ってツールの特定の部分を消す

消したい部分があるツール本体をA、

消す形状のツールをBとすると、

1.Tool > SubTool 上で、

A

B

となるように並べる。

A-B.png


2.Bのブーリアン設定を[差]のものにセット

スクリーンショット 2015-08-22 14.22.29.png


3.AをDynaMesh化

Tool > Geometry > DynaMesh > DynaMesh


4.Aを選択した状態でMerge

Tool > SubTool > Merge > MergeDown

5.DynaMeshを更新

ctrl + ドラッグ


やったぜ!


PolyFrameでの分割をやり直すには

適当にalt で選択してcommand + wすればよさそう。



反転したコピーを作り出してくっつける

Tool > Geometry > Modify Topology > Mirror And Weld で軸を指定してコピーができる。

もしコピー後の物体の距離が近ければ、それぞれの断面が接続される。



☆This mesh is composed of multiple subdivision levels.~ って出る

スクリーンショット 2015-08-16 21.54.06.png

2択。


a.Tool > Geometry > Del LowerとかでSubDivisionを一つにしてから実行、そのあとReconstruct Subdiv(試そう)

b.SubTool > Freeze SubDivision Levels してから実行、実行後に戻す(エッジが落ちたりするケースがあるのでダメ


ツールの特定の部分を消す(ポリゴン再生成されるっぽいので全体に影響が出る版)

1.control + shift でマスク

2.control + shift + ドラッグでマスク範囲を反転

3.Tool > Geometry > Modify Topology > Del Hidden


ポリゴンの再生成が発生してるっぽくて、ペイントとかにも影響が出る。

☆全体に影響がでないように消す方法はあるのかな?

→とりあえず消したい部分をマスクしてcontrol + shift (マスクモード)ブラシのTrimCurveを振り回したらなんかできた。

副作用はよくわからん。

Boolでやってもよさそう。



ツールの特定の部分を消す(周りに影響が出ない版)

消したい部分をマスクして TrimCurve。

1.SubDivisionを最低に

2.Freeze Subdivision

3.TrimCurveで消す

4.Freeze Subdivision 解除



現在のツールから別のツールを作り出したい

別ツールにコピーしたい部分以外を選択、

Tool > SubTool > Split > Split Masked Points



☆ポリゴン分割のやり直しがしたい

DynaMeshでいけそう、、



エッジを立てたい

spolish, hpolish ブラシがいい感じ。



☆先端を尖らせたい

(一度やってみて説明を追記すべき)

Revisionを上げておき、尖らせたい先端を選択

-> Tool > Masking > Blur

-> LSym をOn

-> Scale調整

-> Move調整



☆ポリゴンの繋がりをもとにGroupを再構成する

(一度やってみて説明を追記すべき)

Tool > PolyGroups > Auto Groups



☆ポリゴン数情報をもとにGroupを再構成する

(一度やってみて説明を追記すべき)

Tool > PolyGroups > Merge Similar Groups



ポリペイントからマスクを作る

塗る

-> Tool > Masking > Mask By Color > Mask By Intencity

-> Tool > Masking > Sharpen

等。



ポリゴンの上にペイントしたい

zaddをoff

-> rgbをon


プリミティブをモデリングできるようにする

Tool > Make Polymesh 3D



VIsibilityを変更する

ctrl + shift + クリックで、対象と連続したポリゴンなどを特定の法則で表示/非表示にするよことができる。

ctrl + shiftで使用する選択ツールのタイプによって細かい動作が異なる。

SelectRectの場合、モデルを選択すると、PolyGroupに基づいた選択を行うことができる

SelectLassoの場合、モデルの細部まで選択を行うことができる

特にSelectLassoの場合、ポリゴンの辺を選ぶことで、その辺を含むポリゴン横一列とかを選択することができる。

a.png



ツール上にメッシュを貼ってそこからポリゴンを作りたい

Topologyブラシを使う。

1.Topologyブラシを選択

2.ブラシサイズを10くらいに小さくしておく。小さすぎるとポリゴンメッシュつくれないことがあるらしい。

3.面を作りたいオリジナルのツールをコピー、SubDivisionが無いツールにする

4.面を書いていく。

5.書き終わったらツール上の適当な箇所をクリックすると、ブラシサイズに比例したポリゴンが出来上がる。元のツール部分はマスク状態。

6.Tool > SubTool > Split > Split Unmasked Points で別ツールとして出力

7.オリジナルのやつは消しちゃうとか。

スクリーンショット 2015-09-20 1.10.11.png


交点を作ってそれを結ぶ、っていうののバリエーションが欲しいところ。



特定のツールのポリゴンを両面表示にする

Tool > Display Properties > Double をon



ポリゴンのエッジを維持したい

ローポリのモデルをDevideしていくと、そのエッジが潰れてしまう。それを防ぎたい。

マスク -> Tool > Geometry > Crease > Crease で、特定のエッジが保護できる。



ポリゴンのエッジ保護を解除したい

保護しているエッジの保護を解除するには、

Tool > Geometry > Crease > UnCreaseAll


個別のポリゴンを融合させるには

DynaMesh、BooleanのAddで合体させる。など。



ZBrushでモーション用のボーンとかつける

つけられない。別のソフトを使おう。



角を保ったままSubdivideをかける

Tool > Geometry > Smt ボタンをオフにして分割する



やってみよう系


特定の面を押し出す

(やってみよう)

0. 押し出したい面以外を非表示

1. 面を移動させる

2. Tool > Geometry > Edge Loop

これで、中間部分が補完され、押し出しっぽいことになる。



適当な境界線にポリゴン点を追加する

(やってみよう)

0. 特定の凸面をマスクする

1. Tool > Geometry > Edge Loop

2. マスクの淵に新しいポリゴン点が追加される。



表示範囲に対してポリグループを割り振る

(やってみよう)

Tool > PolyGroups > Group Visible



オブジェクト表面を一周するようなポリゴン分割

(やってみよう)

網目に切るような分割が、表面に対して入る。

GroupsLoops を使う。ムービーのポリゴン分割の話の30分あたり。



下のSubDivisionを作り出したい

Tool > Geometry > Reconstruct Subdiv 


なるほどそういう概念だったのか。



まだよくわからん系




ToDo


知り方を得る

1.聞ける人を作る、んでその人に聞く。

2.調べられる源泉を増やす

ZBrush 4R7 新機能解説

Z-Notes

http://momonchan574.blog65.fc2.com


http://momonchan574.blog65.fc2.com/blog-entry-862.html



ZModeler Bridgeって何

このへんに詳しそう。

http://unrealengineand3dcg.blogspot.jp/2015/02/zbrush4r7zmodeler.html



Dynamic Subdivって何

動画があった。これか、新機能解説。

https://www.youtube.com/watch?v=wey8lY9xJf0



モーションつける技術

モデリングある程度まで行ったので、モーションを学ぶ。


プロジェクションについて

学びたいな、なぞってみよう。

http://www.gogogogo.jp/issue/diary/一人大学/モデリング/3834/



wrote 2015/07/21 17:58:54

UnityのEditor拡張でBuiltInのアイコン画像とかを使う


概要

UnityのEditorはなんか頑張って作ってあって、開発者が拡張できるパーツで頑張られている。

んで、Editor上で表示される画像とかはどこかに仕舞ってあって、それを読み込んで使っている。


例えばPlatformのアイコンとか、

スクリーンショット 2015-07-20 0.12.22.png


こういうやつとか。

スクリーンショット 2015-07-20 0.08.25.png



実態はどこにあるか

Macだと下記パスにあった。


/Applications/Unity/Unity.app/Contents/Resources/unity\ editor\ resources

実態は圧縮されてるファイル。

スクリーンショット 2015-07-20 0.23.39.png



Editorからファイルを読み込むには

なんのことはない、Resourcesから取得できる。


var iconResources = Resources.FindObjectsOfTypeAll(typeof(Texture2D));


ってやると、空っぽのプロジェクトで1,000個ちょっとのアイコンが手に入る。

でまあ、名前とか指定して読みたいよね、、?



どうやるんでしょうね? 調べ中。

今のところはとりあえず全部読んでから欲しいやつだけのこしている。

ちなみに


var s = AssetDatabase.GetAssetPath(iconResources[0]);

とかやったら、sには Library/unity editor resources という値が入ったので、

Unityは起動時に unity editor resources ファイルを展開、Libraryフォルダってところに置いてるんだと思う。


たぶん Library/unity editor resources/素材名 で呼び出せるんじゃないかな。

wrote 2015/07/20 0:08:06

Oculusで真面目に遊ぼうと思ってAlienWare15インチ買って売った話


概要

15インチだけかどうかはわかんないですけど、Optimusの実装方法として最悪な手を使ってくれてるみたいで

OculusとAlienWare15の組み合わせはダメでした。



あらすじ

・友人から完全新品で開封してないAlienWare15買わない?って話がきたので飛びつく ・お値段15マンエンくらい。実際安い。

・Oculusつなぐ

Directで認識しない。

・Optimus切らんとダメか~~ってなってOptimusをKillする設定を探す旅に出る

・アプリケーション単位で使用するボードを変更できるので変更、、、が、、、、ダメ、、、!!


・BIOS、 BIOS~~!!

設定項目なし


・フォーラムいろいろ巡ってみるに、

どうもDiscreteなボード -> Integratedなボード、と出力経路が固定されてるっぽい。

はい解散解散~~~



売った

俺のAlienWareか、、? 欲しけりゃくれてやる、、、!! 秋葉原に全部置いてきた、、、!!

もらった時の値段と売り値の差額でPS4買えるわ。



感想

こりんさんのサイトとか見てから物を買おうな。

http://framesynthesis.jp/tech/2013/oculus-rift/


ちなみに自分は見た上で「あーー前世代のやつだったら切り替えスイッチついてたらしーじゃん、いけるんじゃね、、?」ってやって 大爆死したクチ。

wrote 2015/07/08 0:03:03

ノードエディタのコード


概要

サンプル作ろうなって気持ちでとりあえず作った。

NodeEditor for Unity

https://github.com/sassembla/NodeEditor


バグとか知らん。

スクリーンショット 2015-07-05 19.10.26.png


こいつの接続点はボタンで作られてて、クリックすることが可能。

で、接続を切りたくなった場合、接続点をクリックすると接続一覧が出て切れる。便利だ。

スクリーンショット 2015-07-05 23.14.52.png

あとでconnection上に名前を表示するようにしようっと。



参考になったサイト

GUIのButtonに設定できるGUIStyleを探しててたどり着いた一覧。

Show Built In Resources

http://wiki.unity3d.com/index.php/Show_Built_In_Resources


なんでこのページの内容が標準のAPIに書かれてないんだろうっていう感じ。


実際に実行してみたところのサンプル。エディタから情報拾って出してくれる。メッチャ量がある。

スクリーンショット 2015-07-05 13.36.32.png



wrote 2015/07/05 13:31:41

Unityで最高のノードGUIをつくろうな


概要

自前で作ってるタイムラインベースのAI作成ツールのGUIを、Unity用につくっていた。

タイムラインはまあそれでいいんだけど、AIの条件を書くツールとしてノードエディタが要るのはわかってた。


で、その部分のAPIのデザインとジェネレータコードの実装が終わったので、いざコード書くかって感じ。

参考になる書籍はこの世にただ一冊。


Unity 4ライブラリ辞典 エディタ編

http://amzn.to/1zW3XVp


本当にケーゴくんには足を向けて寝れない。

どっちの方向に住んでるのか知らんけど。



ノードエディタの構成

いまここを書いてる

wrote 2015/06/24 12:30:56

Oculus DK2とMacBookの相性は悪い


概要

記録までに。

MacBookにWin入れていろいろやったけど、ディスプレイアダプタがとっても相性悪くて詰んだ話。

いいもん。MacPro使うもん。いざとなったらゴミ箱もちあるいてやるもん!



環境

in MacBook:

Windows8.1@MacBook early 2015 CTO 1.3Ghz

+ Unity 5.1.0f3

+ Oculus Runtime 0.6.0.0


Oculus <-> MacBook間の接続にはアダプタを使用(というかそれしか手が無い)

CHb88ROUEAAGfHN.jpg


Bootcamp版:Unityでのプレイ実行時にエラーで落ちる。やっぱ直に繋がないとダメか、、たぶんアダプタがダメ。

Oculus Utilityでは正常に認識されてるんだけど。惜しいがダメなものはダメ。


VMWareFusion版:ディスプレイは認識されてるけど、USB機器としては認識してないっぽい。

USB機器として認識させられればいけるのでは、、と思うけど、タイムアップ。


in MacPro:

Windows8.1@MacPro 全盛り

+ Unity 5.1.0f3

+ Oculus Runtime 0.6.0.0


Bootcamp版:動いた。うん。速いな。そりゃな。

・Unity入れて、OculusRuntime入れて、動くのかどうか→動いた。

・Bootcamp側なんで、vncでログインできないと辛いな→Wndows8.1Proなら特になにも入れずにできた。

・持ち歩く→笑える



結論

基本、無駄な努力だし特化環境になっちゃってトラブルシュートめんどうそうなので、素直にWindowsマシン買おうな。


wrote 2015/06/14 14:06:13

Oculus 6/11イベント


製品版Oculus

形状とかは写真を見てもらうとして


・2016 1Qに発売

・XboxOneコントローラ同梱(なんだけど別にXboxOne縛りではなさそう。Winメイン。

・専用手持ちコントローラx2

・このコントローラx2の位置もセンシングされる

・さらに、コントローラを握る手のひら自体の状態などをセンシング、指の動きとかを反映させられるっぽい。傾きもいけそう。

・推奨スペックとかは不明



簡単なまとめに。


wrote 2015/06/12 3:04:03

AssetRailsプレゼンテーション


概要

UnityのAssetBundleを、素材から大量に作成するUnityのAsset

AssetRails

https://www.assetstore.unity3d.com/en/#!/content/27672



例えばあるAssetBundleにPrefab画像モデルとかが含まれている場合、


まずは大元になる素材をimport + 特定の処理を施したりして、

・画像

・モデル

その後Prefabを作成し、

・画像

・モデル

・Prefab

特定の組み合わせでAssetBundle化、

・AssetBundle


AssetBundleをServerにアップするためのパッケージング

・AssetBundle + 情報ファイル


までを一手に引き受けて実行できる。



男は黙って実行

Assets/AssetRails/Samples/Resources(AssetRails).zip を解凍

Samples/Resources(AssetRails)フォルダを PROJECT_FOLDER 直下へと移動

sh Assets/AssetRails/Samples/ShellScript/run.sh

→PROJECT_FOLDER に、AssetBundleのファイルとフォルダ一式ができてるはず。



CommamdLine Args

AssetRailsはコマンドラインから動かす。

ので、Jenkinsとかからでも問題なく動く。自動化しような。


各フェーズでの操作と組み合わせが可能。

https://github.com/sassembla/AssetRails-Support/blob/master/CommandLineArgs.md#assetrails-command-line-args


段階的なexport、importが可能なので、やり直さビリティが高い。

例えばimportしただけのやつを試したり。



コードで書くTransformer

難しいことはコードでやろう。

やりやすくなるようにAPI化、分割されている。

https://github.com/sassembla/AssetRails-Support/blob/master/RunnersAPIDocument.md#assetrails-runners-api-document



Versioningというパッケージング処理

過去に作成したAssetBundleと追加部分のAssetBundleを元に、柔軟にリソースを追加、パッケージング、保持できる。

https://github.com/sassembla/AssetRails-Support/blob/master/Versioning.md#versioning-in-deep


あたらしいversionここで振ることができるんやで。運用に際して楽。


・すでにimport済みのリソースの.metaを使うことが可能

はい。


・実はAssetBundle以外も生成できる

コード全部入ってるので特定のExtendが可能


・versionedList.json はカスタマイズ可能

可能っちゃあ可能



補記 2015/05/18 20:00

・Bundlizerから先を切り出せるのではないか

いきなり全部はデカすぎる


・ノードエディタほしいな?

あると印象変わるよね

wrote 2015/05/18 15:40:04

Rustであそぶ


概要

1.0出たので。


;が嫌いな自分が、初めて「;我慢」してもいいな~~~と思った言語。

というか;の必要な位置の定義が面白い。


letまわりの定義、セット、関数の実行に関しては;が必要。


あと色々とモダン気味。



よさ


tupleな

let (_a, _b) = (1, true);

いろんなのが複数の要素を返せる。返したそばから束縛可能。Pythonとか検索会社の作ってる行くって言語みたい。



型を決めずに初期化から型の固定

let a;

a = 100;

a = false;// これはコンパイルエラーになる


変数の型指定なしでの初期化ができる。


aに何もセットしないまま使おうとするとuninitializeエラーが出る。

良いことだと思う。


これで、インスタンスとか変数を渡して中で何かするメソッドを滅せる。

多数の値を返せるところも、そのマッピングまで一発なので、汚い関数を作るニーズがほぼ存在しなくなるのでは。



{};の扱い

{};は式なので、値を返せる。素敵。

let a = {

100

};

とかが可能。これで、以下の利点が出そう。

・値を設定するための処理が隔離できるのでメソッド化までしたくない組み合わせを特定のコンテキスト内に隠蔽できる

→依存している部分の明示が可能

→過度の抽象化=メソッド化を防げる

→変数名に気をつける文化

→エディタによってブラケット閉じたり開けたりできるので擬似メソッドぽい表現ができる



コンパイラワーニングによる自動的なルールづけ

変数名について、snake_caseとかをちゃんとやらないとコンパイラがWarnでやんわりと殴りかかってくる。

良い。


macroある

コンパイラプラグインある

実行速度爆速


など。

wrote 2015/05/16 14:02:39

Mac/Win両方で動く(α版だけど) MagicalVoxel Editor


概要

操作が楽なボクセルエディタだ、、


これ

https://voxel.codeplex.com



競合としては次のとかがあるらしい。自分は使ったことが無い。

qubicle

http://www.minddesk.com


こちらもMac/Win両方で動くぽい。



今のところ

save機構とかはMacだとまだ無いのかこれ、、フロッピーディスク的なボタン押してもなにも起こらない。

export機構も存在はしてるんだけど、特に反応し無いかっこよさがある。

obj行けるっぽいけど特に出力できなかった。


Winだとできるんだろうか?

ちなみに最近まで更新されてる。期待。


ハッカソンとかでのモデルのボリューム作成とかによさそう。


スクリーンショット 2015-05-06 10.41.21.png


wrote 2015/05/06 10:44:02

Disqueメモ


概要

訳した。

https://github.com/antirez/disque

とりあえず使ってみて俯瞰で訳したみたいな感じなんだけど、ひたすらGoogle翻訳と相性の悪い文章だった、、、


間違ってそうなところあったら優しく教えて欲しい。

あ、プルリクしてくれると楽。rtf or rtfdが日付フォルダに入ってるのでそれを更新してpull-reqくれれば嬉しい。

https://github.com/sassembla/Public/tree/gh-pages



Give me the details!

DISQUEは、プロセスの間でメッセージを交換する中間層として機能する、分散型のフォールトトレラントなメッセージブローカーです。


producerがconsumerに提供されるメッセージを追加します。

メッセージキューはしばしば遅延ジョブを処理するために使用されるので、DISQUEはjobという単位をAPIとかドキュメントの中で使っています。

とはいえ、実際のjobとは、​​実際には文字列の形で扱われる単なるメッセージなので、いろんなケースで使えると思っています。

この文書内では、「job」と「message」が示すものはイコールな感じです。

producer-consumer モデルとジョブ・キューはかなり似ているので、悪魔は細部​​に宿るような感じになりました。 


DISQUEについての詳細は、次のとおりです。


DISQUEは同期的に複製されるジョブ・キューです。

キューに新しいjobが追加された際、クライアント(producerかconsumer)がそのjobについて確認できる状態になる前に、メッセージはW個のノードに複製されます。

W-1個のノードに障害が発生しても、メッセージを配信することができます。

DISQUEは「少なくとも一回」と「最大1回」の両方の配信セマンティクスをサポートしています。

「少なくとも一回配信する」、という部分にメッチャ力を入れました。

「最大一回」はretry time を0にセットした際の結果実現できる(決して再びメッセージを再キューイングしない) + replication 要素を1にセット(厳密にはこの設定必要ではないんだけど、メッセージの複数のコピーを持つのが無駄なので)という設定で実現できるようになっています。

これらはメッセージごとに設定が可能なので、同じキューやノードに対して「少なくとも一回」と「最大一回」という設定を同時に持つことができます。

DISQUEは障害のただなかにあっても、「少なくとも一回」配信が可能なように設計されています。

これは、「DISQUEは最低でも一つか、それ以上の回数の配信を保証することができるが、可能な限り過剰な配信を回避する」、ということを意味します。

DISQUEはすべてのノードが同じ役割を持つ分散型のシステム(マルチマスターとか呼ばれる感じのやつ)です。


producerとconsumerは、彼らが好きなノードに接続することができるし、同じキューに対してのproducer, consumerである必要がありません。自動的に同じノードへの接続を維持します。ノードはロードとクライアントの要求に基づいて、メッセージを交換します。

DISQUEはCAP定理でいえばeventuallyに一貫性のあるAPとして利用可能です。

少なくとも一つのノードが到達可能であるうちは、producerとconsumerは処理を進めることができます。


DISQUEは非同期コマンドをサポートしていて、これはクライアントにとって低遅延ですが、保証の内容が低下します。

例えばproducerがreplication = 3をセットした設定のキューにジョブを追加した際、そのメッセージを追加されたノードが本当にreplication = 3の設定を果たせたかどうかを知る前に処理を返したい感じです。その際、ノードはベストエフォート型の方法で、バックグラウンドでメッセージを複製します。


DISQUEはとあるメッセージに対して、指定されたretry time後にconsumerがメッセージを処理することができなかった(その通知がなかった)場合、自動的にそのメッセージを再キューイングします。

consumer側がメッセージを明示的に再キューイングする処理は必要ない感じです。


DISQUEは、consumerが確実にメッセージを処理した(別の言い方をすれば、すでに処理されたジョブを通知する)ということを知るために、明示的な通知手段を用います。

DISQUEのキューは、ぶっちゃけベストエフォート型の順序保証を提供します。

それぞれのキューはメッセージの順番をその生成時間から決めています。メッセージが作成されたノードのwallclockが基準になります。

同じノードで作成されたメッセージは通常、作成された順番で配信される感じです。


異なるnodeの異なるwallclockを基準にしてるので、これはまあ一般的なorderingではないです。例えば、次のようなケース。

・メッセージがretry time内で配信されず、ノードのロードバランシングと調停処理を加味して別のノードに再キューイングされた時

(この際、consumerは元のメッセージを作ったのとは別のノードから、そのノードが自分のwallclockで作成し直したメッセージを受け取ることになります。)

しかしまあ、メッセージが必ずしもランダムな順序で配信されるか、というとそうではなく、通常は最初に作成されたメッセージが最初に配信される感じです。

DISQUEは厳格なFIFOのセマンティクスを提供しません。なので、技術的に言えばメッセージキューと呼ばれるべきではありません。正しくは、いい感じのメッセージブローカー、です。

しかし、私は現時点では、IT業界でのメッセージキューは多くの場合、あんまり深刻に考えずに、別に順序を保証することが必須ではないもの、、ようはブローカーとして使用されているんじゃないかな~と思っています。

その意味で、私はDISQUEをメッセージキューと呼んでいいんじゃないか、って考えています。


DISQUEはメッセージのコントロールに際して、3つの時間関連のパラメータを提供しています。あと一個、replicationに関するパラメータがあります。

これらを使って、job(メッセージ)の以下のような要素がコントロールできます。

1. replication 複製: 何個のノードがメッセージの複製を持つか

2. delay 遅延: DISQUEがメッセージ成果物を作り、キューにメッセージを入れるまで待機する時間

3. retry リトライ: メッセージが配信されずに、もう一度キューイングされるまでにかかる時間

4. expire 有効期限: キューの中にメッセージが最大何秒残っていていいか(配信完了、失敗を問わずメッセージ作成からこの時間が経過したらメッセージを消す)


最後に。DISQUEはデフォルトオフなオンディスクでのメッセージ永続化をサポートしていますが、それは1つのデータセンターのセットアップ中の処理や再起動時の処理に便利です。



ACKs and retries

DISQUEでの「少なくとも一回配信」セマンティクスの実装は、特定のケースの障害中でも複数の無用な配信を回避するために設計されています。

複数の配達が発生しないことを保証することはできませんが、それでもまあ、最低でも一回といいつつ複数回の配信を許容可能な(または明示的な処理ができる)ケースがあると思ってます。守れるにこしたことはないんですが。


例としては、ユーザーに電子メールを送信するケースです。(ユーザーが重複した電子メールを取得するとか、まあ、それはひどすぎるってほどの出来事ではありませんが、可能な場合は回避するのが大事ですよね。)


複数の配信をできるだけ避けるために、DISQUEはクライアントACKというのを使用しています。

consumerはメッセージを正しく処理できた際、その事をDISQUEに伝えます。

その際、ACKは複数のノードに複製され、最速で破棄されます。クラスタの中の複数のノードが一つのACKの対象のjobを持っている事は滅多にない状況なので。


メモリ圧力下や、または特定の障害シナリオ下で、ACKは最終的に破棄されます。

具体的には以下のようなケースがあります:

1. jobが複数のノードに複製されたが、普通は一つのキューに一つのノードがあるだけなので、メモリ内にjobがあるという状態とキューイングしてあるという状態には違いがあります。(???)

2. 複数のノードがあるメッセージのコピーを持ち、ACKが得られずに一定の時間が経過した場合、メッセージは再キューイングされます。その際、複数のノードでできるだけ再キューイングが発生しないように努力するようになっています。(なのでACKは結果的に消される、みたいな話?)

3. ACKは、networkに断絶がない状態 + なんの失敗もせずにメッセージが処理された状態だと、最終的に最速で、メッセージのクラスタ間での複製とガベコレが行われます。


もしノードがjobのコピーを持っている状態で、特定のconsumerとjobとの間に断絶があり、それでもconsumerからの通知(ACK)がretry設定時間より先に到達した場合、そのACKはきちんと処理され、メッセージの再キューイングを避ける事ができます。

同様に、jobは最低でも一つのノードが利用できる場合、ACKを受け取る事ができます。また障害復帰時、そのACKはまだメッセージのコピーを保持している他のノードにも通知されます。

このようにACKは、複数回の同じメッセージ配信を避けるべく、何回か複製/再作成が行われる、メッセージが配信されたことの証明になっています。実際。

すでに述べたように、複製や再試行を制御するために、DISQUEジョブは、次の関連プロパティがあります。複製、遅延、再試行、有効期限についてのやつです。

retry=0なjobは、キューに「一回のみ」保持されます(このケースだとreplicationが1より大きくても無意味な感じになり、もしセットしたらエラーが出ます<訳注:本当に出るのか試したことないや。何ていうエラーがでるんだろうな>)。


で、そのメッセージは一発で配信されるか、配信失敗して未達のまま残るかします。

jobがディスクに保持されている間は、キューはそれらを保持しません。この動作は、永続化設定が何であれ、複数ノードがクラッシュから復帰した際に保証されています。


ただし、たとえばアップグレード時などにシステム管理者によってノードが手動で再起動された際には、キュ​​ーが正しく保持され、この場合はストア/ロード操作がatomicなので、スタートアップ時にリロードされます。この時レースコンディションが発生する可能性はありません(jobがすでにclientに送付され、そのjobが同時にディスクに保存された場合を除く)。



Fast acknowledges

DISQUEは、FASTACKコマンドという「処理されたメッセージを確認するためのより高速なACK」をサポートしています。

到達通知についてガチで考えた場合、メッセージがノード間で交換されることから、それはとてもつらい手法になる感じです。


通常のACKコマンドの動作は以下のような感じです:

1. クライアントが1つのノードAにACKJOBを送信

2. ノードAは、コピーを持っている他のすべてのノードにSETACKメッセージを送信

3. それに対してすべてのノードはGOTACKで答える

4. ノードAは、最終的に他のすべてのノードにDELJOBを送信


注:なんらか失敗が発生した場合の実際のガベージコレクションはもっと複雑で、あとでステートマシンの説明が書いてあります。上記の進行で処理時間の99%にあたります。


メッセージが3つのノードに複製されている場合、重複した配信を避けるために真面目に頑張るならば、その到達通知には 1 +2 +2 +2のノード間の通信を必要とします。

で、FASTACKは、信頼性が低いながらとても高速で、より少ないメッセージ交換を行うように考えられています。


FASTACKは以下のような感じで動きます。

1. クライアントは1ノードにACKJOBを送信

2. 受け取ったノードは対象のjobを破棄、ノードがjobを認識していなかった場合はコピーを持っている可能性のあるすべてのノード か すべてのクラスタに対して対象jobのDELJOBを送信


ネットワークの断絶などによって、配信完了の通知がメッセージのコピーを保持しているノードに到達できない場合、そのノードは復帰時に、「すでに配信され、破棄されたはずのメッセージ」を再度配信してしまう可能性があります。これは、誰もそのメッセージが「すでに配信されたものだ」という情報を持っていないために起こり得ます。


あなたが使用しているネットワークの信頼性が非常に高い場合は、パフォーマンスに対して関心が向いているでしょうし、別に複数回配信されても困らないんじゃないでしょうか。というわけでFASTACKは有効な手段だと思っています。



Disque and disk persistence

Job IDs

そのうち気がむいたら。

wrote 2015/05/04 13:59:32

Disqueを使って遊ぶ


概要

redis作ってた人が作ってるよ~って言ってた分散メッセージブローカーがgithubにきてた。

disque

https://github.com/antirez/disque



まだα版だよみたいな感じ。



make

依存が無いのでmakeするだけでokなはず。

OS X 10.10.3 とかでそのまま動いた。

ビルドしたバイナリはsrc中に出来る。



serverたてる

disque-server をぶったたくと起動する。

初期ポートは7711になっている。このへんはconfがついてるのでそのへんと合わせてセットみたいな感じ。

スクリーンショット 2015-05-03 18.04.15.png



備え付けのコマンドラインインターフェースをつなぐ

disqueのserverに対して対象となるport指定でcli-clientを起動できる。

disqueのclientは複数のserverに対して通信をすることができる。(multi-masterってこの事か

スクリーンショット 2015-05-03 18.11.09.png

コマンドの単位とかなんかまだ変わりそうな気がする。

addjob queueName messageBody 0

で、addjobでqueueNameという名称のキューに対してmessageBodyというメッセージを送っている。 最後の0は timeout



getjob from queueName

で、queueNameというキューからメッセージを受け取っている。


Regisのpub-subとかと異なるのは、

・subscribeのための準備処理がない(メッセージブローカー一筋! 単一用途だからな!)

・複数のmasterを起動時に指定して持てる

というあたり。


複数のmasterに対して誰かがaddjobでjobを投げて、複数のmasterに対してgetjobしてる誰かが受け取る、という仕組み。

producerとconsumerそれぞれの動作ができるよ、という感じか。

仲介として、server側で、nodeという単位でメッセージのreplicationとか保持が行われる。


んで、multicastがしたい時とかどうやればいいんだろう?

→addjobする対象( = ターゲットとなるqueue)を増やす。

なるほど。



ちょっと使って良いなーと思ったところ

client側から指定できる、node自体の溜まってる内容をチェックする仕掛けがあること。

addjob オプションの maxlen がそれ。

試しに maxlen を2とかにして複数回addjobしたら、client側がエラーを得ることができた。

これで、送信者側からキューが詰まってるかどうか楽にわかる。もちろん上位での監視は別途必要なのだけど。


機構的に、役割の割り振りをclient-serverでどうやったら最速になるか、というのを、

多重配信の可能性を残しつつも最低でも一回行う、というのを基礎に組んでいる感じ。


順の保持を完璧までは頑張らない + 障害中とかで復帰時に同じメッセージを複数回受信する可能性があり得るため、clientのやるべき事がちょっとある。

(順の組み立てに関しては諦めていいんじゃないかな~っていう頻度になるような設計に見えた。複数回のほうは何かガード要素を入れる必要がありそう。)

トレードオフでわずかなこれらを残した反面、

ある程度簡潔かつ高速になってるんじゃねーかなーという感じ。



lua client

nginx-lua-moduleから使うので、書いてる。

upstreamに対してaddjob、

このクライアントに対してのdownstreamに対してgetjobを行う。

制御用の機構として、control用のqueueに対してdownstream queue nameを知らせる必要があるっぽい。

簡単ぽい。



Unity client

こちらはC#。とある理由で使うので書いてる。

複数のdownstreamのqueueに対してaddjob投げようと思う。

upstreamのqueueからは聞きまくる。


制御用の機構としてqueueNameの登録をどっかでうけとらないといけないので、control用のqueueについても聞く。

簡単ぽい。



wrote 2015/04/28 17:03:32

atom-shellでファイル無限吸い込み+sync機構を作る


概要

これで話す。

「Electron(旧:Atom-Shell)勉強会 #1」

http://atom-shell.connpass.com/event/13304/


基本的なところは誰かがやるでしょ的な感じで、ツールを一つ作った話。


FileMachineというのを作った

アプリにファイルを放り込んでいくと、リソースを丸っとバージョン管理してくれる代物。

GUIから使いたい、そして適当に管理してほしい、という欲求を叶える。


FileMachine

https://github.com/sassembla/FileMachine


当初goで書いてたんだけど、GUI部分でなんかノらなかったのでAtom-Shellで。


解決する内容

大規模マニュファクチュア~で画像とか3dモデルとかのリソースの置き方にする苦労を消し去りたい。


・デザイナさんサーバにガンガンリソース置きよる

・更新するたび名前変える? ん?? そういう病気??

・日付フォルダ、、ところであれの最新どこ? ああ、一ヶ月前の、、名前、、、違ったんだね、、

・「サーバの容量が逼迫されてきました」あのっあのっ21世紀

下らん。

下らなすぎるぞ。

ヒューマンがしてはならない無駄な努力だ。



挙動

フォルダごとリソースを放り込みまくってバージョン管理できるアプリケーション。


・フォルダを放りこむとどこかに保存

・過去のファイルとMD5とか違ったら新しいrevisionを作り出して保存

・MD5の差がなかったら代わりにproxyfileを置く

・ショートカット(super+oとか)で取り出す

・取り出す際は、最新ファイル全部、とか、revisionを指定して取り出すことができる

・外部からのアクセスエイリアス、外部へのアクセス経路を持つ(外部からの特殊なrsyncとか。Web万歳)

・ファイルIOを直に吐き出して、こんな書き方でファイルの入出力ができてそのまま保存とかできるようにしたい


filemachine -f some.txt | open -a なんかApp.app


ようは完全自動採番でコミットメッセージとか無し、差分比較をbin想定に限定したgitみたいなもの。

分散具合については考え中だけど、分散が実現しないでもいいことができそうなので開発してる。


分散同期に関してはWebRTCが使えると大変ファンキーなのでは? って一瞬思ったけどいろいろやることあってダメだわ。

atom-shellなら通信手段もサーバ能力もあるし行けると思う。



現状

途中までかいてるとこ。


・とりあえず保存と取り出しまでできればそれでいいかなって

実演


1.放り込んだら保存

ファイルは /Users/runnershigh/Library/Caches/FileMachine に自動複製される。


2.super+oで最新をすべて吐き出し

吐き出し場所としてDesktop指定。


3.取り出さずに何が入ってるか? super+iでフォルダ開く。

/Users/runnershigh/Library/Caches/FileMachine とかに入ってる。

んっとんっと、、open in finder どうすれば



why atom-shell

ブラウザっていうviewにもともと依存した環境。

GUI付きのツールが作りやすいと思った。


今回の場合は、もともとgoで作ろうと思ってたんだけど、GUIがダルかったのでatom-shellにした。

FileAPIとかあるししかも通信クライアントそのものだったりもするので、今後通信でファイルをなんとかするのも夢がある。(しかもServer/Client両用

GUIいらないなら別に選ぶ必要無いのでは????

GUIいるならatom-shellでいいのでは?????



使って本当によかったと思うところ

app.getPath まわりの仕様は本当にいいなと思った。

プラットフォームごとのよく使うpathを決めてあるのすごく良い。


マルチプラットフォームでの地獄がよくわかってる人たちが作ってるような気がする

https://github.com/atom/electron/blob/master/docs/api/app.md



FileMachineの未来

・デザイナさんが使えるようなGUI(いれポンだしポン)

・ちゃんとしたコマンドラインな(まだよくわかってない)

・どっかにファイル母体をシンクロさせるようにして、サービス化

・過去のファイルをシュリンクする機構(このままだと無圧縮かつ無限なので差分死する

・マネタイズ

絶対やったほうがいい。クリエイターは自身のクリエイトのためには金を払う。

その金で駆動する。

黄金の回転を目指す。


これの場合はUnityのAssetStoreかな。



TODO

・別名フォルダ入れるとそれ以降そっちを追う楽しいバグ

キャピ(・ω<) 

・削除してしまったファイル/フォルダを追う機能

latest:最新のみ

all:消したものも含めて全て


・ウィンドウからドラッグで取り出したいが??!!?!?!?!

ジッサイできるんかな。


・ファイル単体で放り込みたいぞ?

一発で場所がわかる名前ならそいつに対するチェックのみ行って受け入れ。

もし複数候補が出れば「どれ上書きすんの?」っていう画面出す。

ァッこれきっと作らない。


・フォルダを放り込むの楽しいデザインである必要がある、、、というかリアクションがない

・どのフォルダを放り込むか明示しないとな!

GUIデザインの問題。


・ファイルの名前変更のトラックを視覚化

タイムスリップ的にファイルの変化を追うGUIモードをつくればいいんだと思う。ピアノの鍵盤みたいにするか。

Unknown.jpeg

どちらかというと時系列で同じ名前で別のファイル置くのを楽に扱えて人類が受けるペナルティだけ無くしたい。


・いまんとこ全部syncで書いてる

なんか、、nodeだったら教義的にはasyncで書くのがいいような気がするが、、、すまないな。


・Win、、、、パス、、、ウッ頭が、、、

はたしてWindowsでちゃんと動くのか!!?? どうなってもしらんゾーーーーッ!!

atom-shellのことは信じてるが自分の書いたコードがマルチプラットフォームセーフかどうかは試してないから知らん。

どうぞ。

・アイコン

なんかそのうち。

この辺。

https://github.com/atom/electron/blob/master/docs/api/native-image.md


・remoteとのシンクロ

remoteとのシンクロとかそのへんをホラ。

セットした状態で配ればいいんじゃないかな。


以下メモ


scopeとか

どこまでこのclientでファイルを持つか、のscopeがあると便利そう。

now ~ 1month とか。

この制約はtime-windowなので、必要があればどんどんスライドしていく。

proxy fileが最古のものになったりするので、その際は基底(rev -1) とかをremoteから持ってくるといろいろ解決しそう。


ファイル単位のタイムライン

見たい。

perforceみたく表示したい。金になりそう。




wrote 2015/04/24 19:00:00

Client-Client間のRPCのここが嫌だ


概要

iOSとかで動く対戦型で二人以上のプレイヤーが動くゲームでのClient-Client間のRPCは使いどころ無いので死ねみたいな話。

主にself-definedでないRPCについての文句。


Remote Procedure Call

定義

メソッドシグニチャとかを送って他Peerのメソッドをぶっ叩くこと。


結論から言うと、P2Pでない対戦ゲームでClient-ClientのRPCを使うべきでは無いと思っている。

代表的な嫌なことは下記。代案もある。



Version差で、Client-Serverが引きずられる

独自定義した「わけではない」バイナリを送る感じになるので、クライアント間でのバージョン互換性を保持しないとゲームにならない。

= 全ユーザーのバージョンを保たないといけない

= サーバ側もその制約を被る。

-> いろんなバージョンのクライアントの面倒をみる羽目になる

それは詰み。



データサイズが制御できない

結論から言うとデータ形式をゲームごとに自分で定義したほうがいい。


行動コード + 発行者コード + … とか、すべてbyteで書き、できるだけサイズを小さくする。

っていうのが理想だけど、


開発中は別に中身がJSONとかでも良いと思う。最終的にサイズを小さく、

Clientから送るものはフラグだけ、とかになる。


Serverが送り出すものは、Serverで計算なり発行を決めたデータ になる。

つまりRPCな必要が無い。

ゲームごとに制御したい物事、そのインターバルは異なる。

間違っても「定義されているものを使う」という発想にならないほうがいい。

首が絞まってから何かするのは避けてほしい。



Client-Client間でのRPCは、サーバでの統一がしにくい

Client-ClientでRPCを行うのは以下のようなケース。

1.Client A が歩いた

2.Client Aは、歩いたコマンドを発行(コマンドの対象、タイミングはこの時決まる)

3.コマンドがサーバに到達

4.サーバはClient A,B,C,Dに対して、Aが動いたということを通知

5.Client A,B,C,Dのメソッドが着火され、Client Aが動いたのと同じ状態を作り出す


これは、サーバが持つべき「ゲームの統一動作」という責務に対して、最悪の結果を生む。

全Clientがコマンドを受け取ってダイレクトに実行してしまう形になる。


例えば以下の要件は、本来、すべてサーバが担うべきもの。

・Clientが受け取るコマンドの種類を決める

・コマンドの実行可否を決める

・コマンドの実行タイミングを決める

・コマンドの対象を決める


これをClient主導で行うのがなぜダメか。Serverに実行可能かどうかの判断をする場所がなく、実行中の状態が把握できないからだ。


動かす物事のバランスは、「Serverをまずめっちゃ重く」「Clientを軽く」から始めた方がバランスしやすい

最初は計算や描画など、Serverにできない、重たいことをClientにやらせる。

最初からすべてをClientにやらせると、あとでServerにその実装を移す際に困る。

・ClientどうしでRPCするということは、Serverで何もしていない = Serverになんの実装も無い、ということ

・その処理に同期的な処理(アイテム取るとか移動とか攻撃とかダメージとか要はすべて)が必要になった時、ClientがRPCを止めるのが大変。


Client同士でやっていたことを、Serverが行う必要がでてくるが、その実装はゼロから書く羽目になる。


逆にServerが重い状態から始まれば、「チートされても問題の無い箇所」に対して、どこをClientで行うか、という分散はしやすい。

もともとServerでやらないでもいいこと、というのをClientに持ってくるのが正しい。


ほら、RPC無駄だろ?みたいな。

まあ理想論なんだけど。実際には、全部Server側で実装してから~みたいな無駄なことはしないでいいと思う。ただServer側に倒しておくと、あとで救われる。



まだあるRPCの弊害

・チート対策がしづらい

byteで「このClientで実行した」っていうデータを発行してしまうので、偽造されたら一発。

Serverで状態をもっていれば、「この状態だったらこの入力があってもNをしてる最中なので無視!!」とかができる。

・サイズが無駄にでかい

フラグだったら1bitで済むところ、RPCのシリアライゼーションデータを丸っと送る価値って何。


・途中介入がしづらい

Serverが定義していて把握できるbyte列であれば、「先頭数byteをみれば何だかわかる」という条件があると楽。

だが、これはRPCじゃあないよね。

つまりRPCではなく自分でデザインした方がいいよって話。


・実行がメソッド単位で行われてしまう

APIを組み替える時に常にブービートラップのように事件が起こる。

ダイレクトにClientたちの動作が変更されてしまう。仲介役であるServerを絡ませた方がいい。



一度体験すればRPCがどのくらいクソかわかると思うけど、体験させないとダメ?

他のゲームがどうやってるか、どんなFutureを考えているかを見ることで、

ClientベースのRPCが使い物にならない(=実際に使って良いシーンは無い)ことがわかると思う。

できるだけ無駄な体験に時間を費やしたく無い。



じゃあRPCではなくどうすれば良いのか

Server側で、インターバルを持って物事を処理する。


例えばおしくらまんじゅう有りの、位置が同期するゲームの場合は、以下のようなパターンになる。


A:厳格なタイプ

・Clientがフラグを送る(歩く)

・Client側でそのまま歩くモーションになってもいい

・Server側がフラグを受け取る

・Server側のフレームレートで、各プレイヤーから受け取ったフラグを回収

・Server側で一回のフラグに付きどのくらい歩くかを計算、ぶつかりとかもここで計算

・ServerからコマンドをClientに発行

・各Clientがコマンドを受け取り、移動を実行

Server側にすべての計算結果が残るので、再現も中断も楽勝。

加えてキャラクター間のぶつかりとかも計算できる。

敵が死ぬとかはこのフェーズで行わないと困る。



B:あんま厳格でないが速い、失敗しても立て直すタイプ

・Clientがフラグを送る

・Server側がフラグを受け取る

・Serverはフラグから可否のみを計算、フラグを各Clientにできるだけ速く返す

・Serverは裏でClientと同じ計算をする

・Clientはフラグを受け取って動く

・Serverから答え合わせのフレームデータを各Clientに送る

・Clientはそれを受け取って事実を捻じ曲げ再現する

Server側には時間差込みで計算結果が残り、かつ最速で動くことができる。

プレイヤーが少ないほどより効率ダメージを受けず、効果が出る。



実際には、AとBのミックスで設計することが多い。


Client->Server間のRPCについて

フラグ送付ができればいいので、要らないでしょ

それRPCじゃないほうが後々ラクだよね。


なにが悲しくてServer側のメソッドの情報をClientに持たなければいけないのか。



Server->Client間のRPCについて

ClientのVersionに合わせたRPC書くの?

いらなくね?



こちらからは以上です。

wrote 2015/04/21 14:44:57

いつかチャンスがあったら言うAssetStoreのこと


概要

出してるAssetのバグを直してそれを申請する作業してた。


これ。

AssetRails

http://u3d.as/content/sassembla/asset-rails/



Store画面、説明メッセージがかぶる範囲をどっか書いといて欲しい

毎回なんか困ってる。サイズどんくらいだっけ的な。

あとプレビューにもなんか枠を重ねて表示してくれると嬉しい。



新しいUnityで古いUnityに対応した申請用のAsset作りたい

すごく面倒くさいことを言っている自信がある。




wrote 2015/04/20 22:50:19

Electronのメモ


概要

Atomのこれ

https://github.com/atom/electron


かなりいいとこまでできてた。

動けば文句ない。



いけっ死霊たち


file-object ファイル読むのに使える。

https://github.com/atom/electron/blob/master/docs/api/file-object.md



remote

https://github.com/atom/electron/blob/master/docs/api/remote.md



protocol ハンドラ定義

https://github.com/atom/electron/blob/master/docs/api/remote.md



menu これどこにでんの。

https://github.com/atom/electron/blob/master/docs/api/menu.md



ipc

https://github.com/atom/electron/blob/master/docs/api/ipc-renderer.md

https://github.com/atom/electron/blob/master/docs/api/ipc-main-process.md



dialog 使うことがあれば。

https://github.com/atom/electron/blob/master/docs/api/dialog.md



crash-reporter お世話になってる。

https://github.com/atom/electron/blob/master/docs/api/crash-reporter.md



clipboard クリップボード管理? どうなってんだろ。どこの?

https://github.com/atom/electron/blob/master/docs/api/clipboard.md



window

https://github.com/atom/electron/blob/master/docs/api/browser-window.md



node-module の使い方とか。

https://github.com/atom/electron/blob/master/docs/tutorial/using-native-node-modules.md

wrote 2015/04/19 0:54:34

Goでバイナリファイル蓄積型exe書きたいな


概要

バイナリファイルを無限に放り込めて、どこかオンライン上でのファイルDBを構築、

コマンドラインからhistoryとかrevision指定してそのファイルを引っ張り出せる、

みたいなものがつくりたいんですわ。


そう、すべてバイナリ。jpgとかpngとか。バイナリ。差分比較しないやつ。


モチベーション

binファイルのバージョン管理をgitとかに入れたくない。

そしてフォルダで画像管理とかしたくない。

そもそも差分管理したくない。


ガンガン放り込めるブラックホールが一つ欲しい。


放り込んだらどこかにsyncされる、

最新取得で最新が返ってくる、

範囲取得で範囲のものが返ってくる、


みたいなのが理想。

放り込んだタイミングでrevisionがついて良いと思っている。


ファイルシステム絡みなのでGoで書いてMac/Win動くようになって欲しい。



比較

差分比較はしない。

が、md5とかで変わったかどうかは見たい。

変わってなかったらポインタだけ置く。



名前

FileMachineにしよう。


wrote 2015/04/16 21:54:24

振動言語


概要

R2D2が喋る、みたいなのを振動で「ニュアンスだけでも」発生させられれば、コミュニケーションになるのでは?

Agree、Disagree、他。


AppleWatchで使いたい。

明確な意図として、画面を見ずともコミュニケーションができるとしたら、っていうのがある。


もっと人間がしゃべれるやつ、、、口笛で言語を作ろう。

wrote 2015/04/15 0:57:38

Messaging in Unity with Stact


概要

Unity上で動くメッセージングシステムが欲しい。


クライアント側で、型やインスタンスの存在をベースにした

Messagingを扱えると、楽だ。


Unityだと本来はSendMessageがあるが、あれはHierarchyに映るものにしか干渉できない。 そしてお世辞にも速くない。遅い。



オルタナティブ

Unityに組み込まれているのだと、こんな感じ

http://docs.unity3d.com/ja/current/Manual/MessagingSystem.html



というわけでMessaging in Unity

Stactを使ってやってみる。


Stact

https://github.com/phatboyg/Stact


wrote 2015/04/14 3:02:31

AssetBundle roundtable Day 2nd


概要

自分はもうなんか出し尽くしたんでこう、へえ、みたいな気持ちで席に居ます。



bin2txt

っていうツールがあってAssetの中身は観れるんだけど、

AssetBundleの中身も見たいんだが?


→ソッスね。圧縮されてても非圧縮でも観れるようなツール提供するかも。


わあい。



PrecompiledShaderが動かないケース?

エディタで動かなかったんだけど、シェーダって共通じゃなくなったのかしら?

→うーん共通なはず、、バグじゃね?



Audio系のAssetをaudioじゃなくて.txtとかで扱ってるんだけど、これってイリーガル?

→いんじゃね。ただ音ファイルとかはbinaryだから.binを使うといいと思う。



AssetBundleデータの圧縮とか解凍にハンドラできない?

→暗号化、復号化に関して、そういうニーズがあるのはわかる。なんかするかも。



Manifestを適当に製造したいんだけど(from 俺)

→すれば? テキストやし

アッあっはい!!


→よく考えたらAssetBundleにするルートは無いな!! ハハハおっと時間が尽きたまた今度

、、!! アッ、、アッ、、はい、、、


アプリ入れ直すたびにAssetBundle落とし直すのダルい。ダルくない?

→あっサポートできるかも!! なんかするかも。



、、、、ァ、、、ァ、、、、JSON、、、JSON、、、

→入るけど何か???


俺の中の全ナチ兵が「戦争!! 戦争!!」って言ってる(喜びの表現最上位)



wrote 2015/04/14 19:13:45

Unityのリリーススケジュールの話


概要

走り書き。



Pre5

バグレポとかもらったよな

がんばってみたぞ



5

先月出たな

っっめっちゃ機能足したな


5.1以降について

四半期で.1上がるリリースサイクルを予定



5.1

RuntimeAssertionとか。


5.2

WebGL2

マルチスレッドレンダリング

IL2CPP for Android

more!


カットされっかもしれんけどな!!!



wrote 2015/04/14 15:12:06

Unite2015 RoundTableに巻き込まれた話


概要

ここで強火さんと自分の写真が使われた(もちろん合法)件について、大前さんをおちょくりに行ったらRoundTableに巻き込まれた。

AssetBundle編ということで、Cacheとかに物申したいんだけどオラーって感じで絡んだのがよくなかった。


結果的にはとても面白い。現在進行形で。



AssetBundleの圧縮がDL後に解除される話について

端末にDLしたリソース、その場で自動的に展開されてしまうのが運命だったが、5.1から圧縮状態で置くことができるようになる。

ヘッダー情報のみをメモリ上に展開、必要なAssetBundle内の必要なファイルのみを読み出せるようになるとのこと。


圧縮形式はLZMA -> LZHAMになる。5.1から。すげえ、俺何にもしないでいいや。


LZHAMについていろいろやろうと思ったのが今年のあたま。

自分は野性の男さんのTwから存在を知った。

https://twitter.com/yasei_no_otoko/status/564614755499786241


公式でサポートされるなら、途中まで書いてた記事とコードは不要になったな、、!! 良い。



キャッシュAPIについての不満(from 俺)

WWW LoadCacheOrDownloadについて


public static WWW LoadFromCacheOrDownload(string url, int version, uint crc = 0);



versionってあるけどversionじゃないよね、みたいな話。


新しいAssetをDLしてincrementされたversion値を与えたら、低いversion値のAssetを自動的に消す機構が欲しいんですが

→5系でhashって名前に変わったよみたいな話。


で、過去のが消えないのは残っているんだけど、これ消していいんじゃね?みたいな話。

→Caching.SetCacheOverrideMode(ver上がったのが入ったら古いのを消すモード) or 消さないモード みたいな。


ぜひ!! ぜひ!!!

デフォルトで使えるものが増えるとうれしいんで!!


あとUnityの中のひとにもUnibook2の俺の章読まれてたのでそれはとってもうれしいなって感じだ。



Cacheしてるファイルが多いとCaching.readyがtrueになるのが劇遅になる問題

知らなかった。そんなことあるんだな。

2000ファイルくらいあると、Caching.readyがtrueになるまでに1秒くらいかかるらしい。


バグじゃね?とのことで、今後なんかあるんだと思う。

確かに2000ファイル程度で遅いのなんかおかしい。



MassProduct作成向けのフローを作って欲しい(from 俺)

素材からAssetBundleを作る、みたいなパイプラインがUnityについてくれるとうれしいなという感じ。


Editor上で個々のAssetBundleが作りやすくなることはうれしい、のだが、

N個のモデル x M個のテクスチャ とかのAssetBundleを用意するか? Unity上で??

という。

んでそのために今年のお正月を捧げて作ったわけですよ、AssetRailsを。

https://www.assetstore.unity3d.com/en/#!/content/27672


ルール、規約ベースでAssetBundleが「素材から」「コマンドラインで」作れるやつ。



無駄に苦しむのが嫌なので、Rail(Plipeline)を作っちゃったんだけど、Unityでそういうのを目指すことは無いんだろうか?

→なるほど。その方向は考えてなかった。

→いろんな会社のやつ見て考えてみたい、っていうかAssetRails知らなかった


はい。ですよね、、知らんよな、、、見た目ダサいしな、、

今度プレゼンするよ。



5系からTypeTreeがAssetBundleに入るようになったので、後方互換性はあるみたいな話

LZMAはLZHAMでも解凍できると思う。

下位互換はケースによってはやばい(クライアント側が古いみたいなケース)

なので、クライアント側が古いけどアンパンマン!新しいAssetBundleよ!みたいなことをするとヤバそうという話。

まあそれはそう。



IL2CPPのパッチに関しては4系のほうが適用が早い

とのこと。


5.1

時期とか話にでてたけど、詳しくは明日のroom1、 4thセッションで。



LoadFromCacheOrDownload と、CreateFromFile

ヘッダ情報を読みだして、AssetBundle内の本当に必要なものだけを読むようになる。

全部をメモリ上に展開しておくという動作ではなくなる。


素敵!! っていうかそういう設計のほうがいいだろJKでもありがとうみたいな感じ。

一つのAssetBundleを作るとき、それらをフルに使いきるべき、使いきれる組み合わせでBundleにすべし、みたいな呪縛が消える。



今日言えなかったこと

明日もあるんだけど、忘れそうなので書いておく。

以下2つ。



1.Importした画像ファイルをUnity内でノーオーバーヘッドでコピーしたい

Importが終わったファイルには、Unity内でIDが振られている。

で、それはAssetか?というと、Assetではない。

よってノーオーバーヘッドでのコピーができない。

コピーができないと、一個のリソースから別のリソースを作るとき、オーバーヘッドが悲しいのでなんというかはい。

以前試した、ここのあたりが詳しい。


UnityでのAssetになった画像ファイルのコピーでインポートを避けることは出来ないという結論

http://sassembla.github.io/Public/2015:01:08%2010-26-50/2015:01:08%2010-26-50.html


こんな問題抱えてるの俺しかいないはず。


で、Import済みのリソースをコピーできる(Unity内でのAssetではない物体のDuplicate)とうれしい。

再Importのオーバーヘッドを減らせる。

それ以外にも、モデルとかに関してもいろいろできるはず。



2.標準でJSONライブラリください

あのっあのっ


何度目だろう。ください、、くだs、、、

あると、、、その、、、なんだ、、、、楽、、、、、

というか他のライブラリが含まれているのが面倒くさくてですね、ええ。

たとえばクソみたいな広告やさんだと、ライブラリのネームスペース変えずにブッコンでくるんですよええ。ええ。

おかげでDuplicateしてんぞオラってビルドエラーになるんですわ。ええ。ええ。


デフォルトの力をみせてくれ、、、



おまけ:今回の提案での自分のスタンスを書いておく


・デフォルトで用意されているAPIが素晴らしいならできるだけデフォルトを使う

非カスタマイズ厨なので、頑張らないのが正義。


・デフォルトが残念な場合、可能であればデフォルトを素晴らしいものにする

逆割れ窓理論。良いものは良い使い手を作り出す。逆にAPIのデフォルトがクソだとそのプラットフォームは大変だ。逃げよう。


・最低限自分が得をする行動、提案をする

何処かの誰かが得をするかも、みたいなのはあんま信じない。最低限自分が得をすべき。レベルが低かったら誰かが殴ってくれることを信じている。


・作った人達の意図を最大限探求する

使ってみて合わない場合、意図を汲み取り損ねてるだけの可能性が結構ある。そんで意図を知るとなるほどってなる場合がある。

なるほどってならない場合もある。


・意図が合わないなら初めて作る

みたいな。




wrote 2015/04/13 19:06:37

ライティングとRealtime GIの話


概要

Unity5でのライティングとRealtime GIの話 by けいじろうせんせい。

なんとなく使えてるけどこの設定あってるのか? を解消していくお話。



ライティングの新機能

Ambientの強化があった。


Skyboxと太陽

Skyboxのプロシージャルが可能になった。

Skyboxを作って、Sunのところに特定のDirectionalLightをセットすることができる。


パノラマからCubemapを作る

HDRから読むことができるんで、.hdr拡張子の画像を放り込む→TextureのタイプをCubeMapに変更、という感じ。

あとはLighting > CubeMapの読み込みで、あっという間に。



CastShadows

Two Sided

洞窟とかでポリゴン一枚でも影が落ちる。いままで両面ポリゴン貼ったりしてたのが不要に。

ソフトシャドウの角度

設定できるっぽい。


アーティファクト(平面に発生するモアレというか、ねんりんみたいな奴)を消す

バイアス方式

影のオフセットをずらす→やりすぎると影がオブジェクトから離れる


ノーマルバイアス方式

オブジェクトを逆の法泉方向で小さくして、そこから影を出す→やりすぎるとオブジェクトに隙間ができたような影が出る


それぞれ使って効果がある場所が違うのでいろいろ試そうな



ここからRealtime GIの話

UnityのGIは、固定物の描画に対して、どのくらいなにが反射するか、を計算するもの、

なので、staticなオブジェクトに対してstaticフラグをセットすればGIが有効になる。


ダイナミック(非static)なおっさんとかにGIを適応させるには、LightProbeを光源が変化しそうな場所に置く。これで、GIの影響(間接光)がstaticでない物体にも反映される。


Specular、テカテカしたものに対するGIは、ReflectionProbeを置くことで対応。

なんもしないと、「あれっ天井がある空間なのにブレスレットが青く光るぞ、、、?!」みたいな目にあう。

それは天井の向こうの空(CubeMapとか)が写り込んでるんだぜっていう話。


DirectionalMode

物理ベースレンダリングのUnity5のデフォルトだと、どの程度光るのか、という情報のみが入ってる。

で、DirectionalModeの設定を調整すると、追加情報として方向の情報が追加され、

反射光が当たる物体の法線を生かしたライティングが行われる。


Directional Specularにすると、さらにSpecularの情報を追加することができる。


ただし、Directional、Directional Specularだと、代表的な光のみを考慮する仕掛けになっているので、複数光源には対応できない。そのへんはLightProbeとかで対応するといいのでは



ReflectionProbeのオプション

CubeMapの角またぎをやわらかーいものにする。

具体的には環境テクスチャの切り替えが透明度付きアニメーションみたいになる。



反射の反射についてのオプション

メタル球を並べると、お互いに映り込む球は「真っ黒で描画される」。

リフレクションの回数を指定できる。


このへん紙にコピックとかで車のレンダリングしてた身としては身震いする感じ。トラウマで。



BoxProjection

箱の範囲に物体があるという前提であれば、無限遠のCubeMapよりは素敵な見た目ができる。モバイルでは使えない。




ざっくり書き起こしまでに。

けいじろう先生の話はとても「効果の説明」と「原理の説明」のバランスがいいので、

NHKあたりで毎週やってくれないだろうか。


課金してしまいたい。

wrote 2015/04/13 15:08:27

MacBookをUSB Type-Cでモバイルバッテリーにつないで充電とか(更新)


概要

まともっぽいUSB Type-C to USB Type Aケーブルが届いたので、

モバイルバッテリーとか、電源プラグ、他端末に対して、充電できるかどうかいろいろ試してみていた。


結果的には使用中のアプリケーションの電力消費状態にまで影響受けるのがわかった。

あとAnker Astro3すごい。4,000円くらいでMacBook稼働中でも3時間くらい作業時間伸ばせて、しかもその間もれなく充電されてる。



試した組み合わせ

1.MacBookとモバイルバッテリー

IMG_0994.JPG

2.MacBookとMacBook Airとか

IMG_0996.JPG

3.USB-電源プラグ(2.4A出るiPad用) + USB Type-Cケーブル

IMG_0992.JPG

4.Anker Astro3 (4A出るやつ)

スクリーンショット 2015-04-19 1.12.54.png


結果としては以下のような感じになった。


1.MacBookとモバイルバッテリー

-> 給電中状態に落ち着く


2.MacBookとMacBook Airとか

-> 給電中状態に落ち着く


3.USB-電源プラグ(2.4A出るiPad用) + USB Type-Cケーブル

-> 充電中状態になることが多い

-> アプリケーションによる消費電力が大きい条件下だと、充電中状態と給電中状態を彷徨う可能性がある。


4.Anker Astro3 (4A出るやつ)

-> 常に充電状態になる

-> 動作中でも最大3~4時間くらいMacBookの動作時間が延長できそう。しかも給電ではなく充電。

-> 動作してない状態 = sleep中とかだとものすごい勢いで充電してた。



給電中状態について

「モバイルバッテリーの仕様に依る」のだと思うが、最初充電できてたけどすぐ給電オンリーになる、というのがあった。

給電中は下記の状態になる。

スクリーンショット 2015-04-12 15.54.52.png

どこまで給電の部分でMacBookの電力消費を相殺できているのかは、パッとはわからなかった。



充電中状態について

純正のアダプタ、あるいはUSB電源プラグ + USB Type-CをMacBookに接続して少しすると、

まず充電可能かどうかの判定がなんかあって、

スクリーンショット 2015-04-12 16.05.05.png

スクリーンショット 2015-04-12 16.32.06.png

このように、充電完了までの時間がでたり、表示が変化する。


この状態になると充電が可能になるが、MacBookで使用中のアプリケーションの電力消費が大きいと、

純正アダプターと非純正のもので差が出た。


たとえばめっちゃ大量のファイルをDropBoxに追加して同期をとる、とかやると、

純正アダプターだと充電状態のままだったのに対し、

非純正の組み合わせだと、「給電状態に落ちた」ことがあった。


うん、電源消費が激しいアプリケーションがある状態下だと、変動するっぽい。


4A出るAnker Astro3だったら、問題なく充電状態が継続し続けた。



wrote 2015/04/12 16:24:16

MacBook (early 2015) 移行用


概要

移行したあとにインストールしたAppのURLをメモしておく。

GUIあるやつのみ。homebrewでのインストールは数えない。



MacDown

http://macdown.uranusjr.com



MailBox(ずっとbeta)

http://www.mailboxapp.com/download/mac/



Unity

5はDLManagerあるからどうでもいいんだけど、4系はAssetのために必要。



Github for Mac

https://mac.github.com



以下はAppStore

Dash

Pixelmeter

iDraw

Twitter



AppStoreからのDLの自動化が出来ないかなあ。

wrote 2015/04/11 16:48:39

リップチャット、あるいはフェースエモーティコン


概要

作ってるがこれ面白いな。




wrote 2015/04/09 12:18:40

箱用の記号集


概要

まったくもって鬱陶しい



│ ┃


┨ ┥ ┤ ┫


┣ ┠ ┝ ├


┌ ┏


└ ┗


┼ ╋ ┿ ╂


┐ ┓


┘ ┛


┻ ┷ ┸ ┴


┳ ┯ ┰ ┬



wrote 2015/03/22 18:39:29

UnityのEditor上で動くpubsub用Server context を作った


概要

あるとゲーム試すの楽になりそうなので組んでみる。

こないだ作ったnginx-lua-moduleでのpubsubのしくみ


nginx-luajit-websocket-pubsuber

https://github.com/sassembla/nginx-luajit-websocket-pubsuber


で、

Client -> (バックエンド) -> redis -> Server contextになるわけだが、


もしも、このServer contextをUnityのEditorで実現できると、

ClientもServer contextも、一つのUnity上で動かせる感じになる。これはラクじゃね?


つまりゲームコードとサーバコードを一カ所、Unity上で編集できる。

あくまで実験だが。



Editor側に来てほしいもの

ClientはUnityのPlayer側に任せるとして、


nginx-luajit-websocket-pubsubberがredisをqueueに使っているので、

Editor側で請負いたいのは、redisのpubsubを捌く機構。


upstreamはこんなの。

Client -> (中略) -> redis-pub -> redis -> redis-sub -> Server context

downstreamはこんなの。

Client <- (中略) <- redis-sub <- redis <- redis-pub <- Server context


なので、Unity EditorのコードでゲームのServer側コンテキスト書いて、

あとはpubとsubが出来れば、バックエンド機構の立ち上げは別途必要として、下記のような構造が作れそう。


スクリーンショット 2015-03-25 4.09.20.png


、、うん、わかんねえな?

要は、一台でもUnity EditorでServer contextが動いていれば、nginxをWebServerとしてClient1~3とやり取りできるようになる。

Client1とUnity Editor Server context は一つのUnity Application上で動かせる。


nginx-luaでWebSocketServeしたりしてると、各ClientがLAN内で一台のUnity EditorのServer context と接続されて、ゲーム試したりとか出来る。

しかもServer context はUnity上で動いているコードなので、適当に編集可能。

Clientとやり取りするデータの型とかの共有も可能。


まあ編集するたびに更新されるんだが。リセット命令は必要だと思うけど今回はめんd


出来上がった物がこちら


UEaaS

https://github.com/sassembla/UEaaS


ひどい名前なので気に入った。

そのうち正気に戻って付け直すと思う。



機能とか特性とかは下記。


・redisでpubsubしたデータをUnityEditor内でsubscribeしたりpublishしたりする

・EditorコードなのでUnity起動したらそのまま動いてる

・redisの先にClientが居れば、データが届く

・payload部分はjson、それ以外のroutingとかpublish先の限定はbyteで書き込まれ、Clientに到達するのはデータのみ

・Clientのログを集計できるような命令乗っけといた


Unity上で編集の必要がある全部のコードが弄れるようになった。とりあえず足がかりとしては満足だ。

ざっくりClient-Server間はstringでやり取りするように書いたけど、だいたいbyteで操作してるのでmsgpackへの変更も可能。



そしてこれで、Server contextをluaで書かなくてよくなる。


wrote 2015/03/22 18:16:51

Unity5Lightmapで遊ぼうというかBake


概要

慣れる意味でいろいろな方法でBakeしたりしなかったりしてみる。

一応Githubに上げておいた。

Lgh

https://github.com/sassembla/Lgh



パターンバイパターン

シーンに置かれたLightのBaking設定、

Sceneに置かれたObjectのLightmap Static 設定、

Lighting > Scene > Ambient GI の設定 をそれぞれ行い、


どう見えるのかとかを整理してみた。


比較環境を作り出す手順はすべて一様で、以下。

1. PlaneとCubeを作る

2. CubeをPlaneの子に入れる

3. Plane, Light, Lightingのパラメータを変更する

4. PlaneのPrefabをつくって新規シーンで読み込み、lightmapの有無を見る


全3パラメータ、2x2x2の8パターン。


1.0_Lrt_nonst_SAGrt 2.0_Lrt_nonst_SAGb

1.png2.png


3.0_Lrt_st_SAGb 4.0_Lb_st_SAGb

3.png4.png


5.0_Lb_st_SAGrt 6.0_Lrt_st_SAGrt

5.png6.png


7.0_Lb_nonst_SAGb 8.0_Lb_nonst_SAGrt

7.png8.png


結果を表にするとこんな感じ。

スクリーンショット 2015-03-21 20.09.55.png

オブジェクトの状態をstaticにして、colorが微妙に変わっちゃうのは何でなんだろう。



とりあえず

実際にBakeされたオブジェクトをPrefabにして別シーンに放り込んで、そのシーンのLightのBaking設定をBakedにしてみたところ。

画面左奥のものがBake済みのもの。手前のオブジェクトはstaticではないモノ。

スクリーンショット 2015-03-20 1.06.00.png


Lightの設定がBakeなので、Bakeされた物体のみが光源計算されている。

Plane1 > Cubeを動かしても、影が再計算される。

Continuous Baking はcheck入り。

Lighting > Scene > Ambient GI はRealtimeのまま。

ということで、

・よそのSceneでBakeしたPrefabも、lightmapの情報を持ったまま他のシーンに持ち込める

・その際、Bakeに使ったSceneに関連するファイル(Lightmap-0_comp_dir, Lightmap-0_comp_light)は不要。Prefabから参照されてないみたい。


Light のBaking設定について

これ。

スクリーンショット 2015-03-19 22.56.53.png


Light のBaking設定は、

Realtime: なんでもかんでも加算、Bakedなモノでも無差別に明るくなる

Baked: Bakedなモノに干渉しない、他も照らさない

Mixed: Bakedのモノには干渉しない、他を照らす


という結果になる。



SceneのAmbient GI設定について

LightのBaking設定に似ている。

スクリーンショット 2015-03-19 23.31.32.png


Lighting > Scene > Ambient GIの設定は、

Realtime: なんでもかんでも加算、Bakedなモノでも無差別に明るくなる

Baked: Bakedなモノに干渉しない、他は照らす

という結果になる。


なぜ時々茶色くなるのか

シーンを開き直したら、あれ、茶色い。

スクリーンショット 2015-03-19 23.02.49.png

みたいな時無いっすか。自分ときどきビビるんだけど。

スクリーンショット 2015-03-19 23.04.28.png


Lighying > Build するか、

Continuous Baking のチェックを入れると結局Lighting > Buildをやったのと同じになって、色味が戻る。

Continuous Bakingのチェックがすでに入っていても、Sceneを開き直した際に反映されない事があるので、

チェックを入れ直すと反映される。

スクリーンショット 2015-03-19 23.06.58.png

はい。ヌッガーーーー不完全だなァァアアアア!!!!



真っ黒になって死ぬ

シーンを開くと真っ黒になっててヒッてなる。

こんな感じこんな感じ。

スクリーンショット 2015-03-19 23.18.11.png

Baked したものだけが真っ黒な状態で表面カリッカリやぞみたいな時がある。

右の方のキューブが白いのは、こいつはBakeを使ってないから。

完全なUnityのロードエラーなのでは?? と思っている。

このへんも、

Lighying > Build するか、

Continuous Baking のチェックを入れると結局Lighting > Buildをやったのと同じになって、失われた色が戻る。

やったねたえちゃん!! なんとか何も問題が無かった事にできそうだよ!





wrote 2015/03/19 17:08:36

Erlang書くIDE


概要

がんばりたくない。

PyCharmに下記をぶちこんで済ませる。

intellij-erlang

http://ignatov.github.io/intellij-erlang/



内容

下記からzipをDLして、

https://github.com/ignatov/intellij-erlang/releases

IntelliJ開いて、Preference > Plugins > Install plugin from disk から、さっき落としたErlang.687.zip を選択。

読み込み終わるとこんな感じ。

スクリーンショット 2015-03-17 12.42.27.png



、、だったんだけど、内容的に満足できる代物ではなかったので、今度金に換えられる用途としてなんかする。そのほうがモチベ湧く。

wrote 2015/03/17 11:14:06

nginx + lua + webSocketでかんたんpub-subサーバ


概要

実験用に簡単に使えるWebSocketバックエンドが欲しかったので、

ngx + ngx_lua_module からのゴリ押しで作ってみた。


sassembla / nginx-luajit-websocket-pubsuber

https://github.com/sassembla/nginx-luajit-websocket-pubsuber


構成

nginx 1.7.10

ngx_lua_module 0.9.15

redis 2.8.9


luajit 2.1 alpha

websocket protocol + server

redis connector

other


動作内容

nginx-luaでは、リクエストごとに完璧にisolateされたluaスクリプト動作が発生する。


たとえばWebSocket受ける場合、

プロセスをwhileでがっちりブロックしてレスポンス返さずにWebSocket接続という形になった。


https://github.com/sassembla/nginx-luajit/blob/master/bin/lua/client.lua#L69

-- start websocket serving

while true do

local recv_data, typ, err = wb:recv_frame()


if wb.fatal then

local jsonData = json:encode({connectionId = serverId, state = STATE_DISCONNECT_1})

pubRedisCon:publish(IDENTIFIER_CENTRAL, jsonData)



で、luaのコンテキストがリクエストごとにisolateされてるとは言っても、pub-subみたいなことをしたい場合、中継がなくて困るので、

中継にredisのpubsubを使っている。


redidのpubsubにpush性能は無く、こちらも単に、特定のキーのsubscribeをwhileループで行っている。


https://github.com/sassembla/nginx-luajit/blob/master/bin/lua/client.lua#L114

-- subscribe loop

-- waiting data from central.

function subscribe ()

while true do

local res, err = subRedisCon:read_reply()

if not res then

ngx.log(ngx.ERR, "redis subscribe read error:", err)

break

else

-- for i,v in ipairs(res) do

-- ngx.log(ngx.ERR, "client i:", i, " v:", v)

-- end


もちろん一個のリクエストプロセス中で2個while書けるはずなくて、ngx_lua_moduleから使えるthread生成を頼っている。


https://github.com/sassembla/nginx-luajit/blob/master/bin/lua/client.lua#L60

function connectWebSocket()

-- start subscribe

ngx.thread.spawn(subscribe)


-- send connected

local jsonData = json:encode({connectionId = serverId, state = STATE_CONNECT})

pubRedisCon:publish(IDENTIFIER_CENTRAL, jsonData)


-- start websocket serving

while true do

local recv_data, typ, err = wb:recv_frame()



中央部分と残念なとこ

redisでpubsubを使って、client x n -> central, central -> client x n を繋いでいる。

つまりredisのpubsubが2系統ある。


で、clientはWebSocket接続なわけだが、centralは、

httpで通信してきたプロセスをredisのcentral pubsubのためにガッチリ拘束する、っていう残念な方法を取っている。


https://github.com/sassembla/nginx-luajit/blob/master/bin/lua/controlpoint.lua#L99

function main ()

-- start waiting loop

while true do

local res, err = subRedisCon:read_reply()

if not res then

ngx.log(ngx.ERR, "failed to receiving data from clients, err:", err)

ngx.exit(500)

return

else


つまり現在の構造は、以下の順でしか動作できない。

1.httpでcentralのパスにアクセス(この通信は帰ってこない)

2.適当にWebSocket接続

3.中央コンテキストでいろいろできる

httpで通信してきただけのやつを停めるのどうなの? とか、それ起動時に自動的にできないの? とか、そのへんを模索しているところ。


副産物

期せずしてredisのpub subに依存したが、これによってclient側へのpushの責務がclient connection側に一任されていて、

送付確認周りをわりと疎結合かつ非同期に作る事が出来た。


つまり一対多のWebSocketのsendにロックがかかっていない。

使っててちょっと楽だ。実用に耐えるとは思ってないけど。


また、redisでの中継でclients - centralを繋いでいるので、clientsからどのpubsubを使うか指定させる事でルームみたいな概念が実現できた。

なかなかおもしろい。


ロックせず、各自のwhileループで回っている部分自体はまあはいって感じなんだけど、redisのpubsubによってタイムラグは若干出ると思う。


client側の実装として、udp版やmqtt版みたいなのも作ってみたい。

まあキューイング部分が全部redisに寄るので、あっさり破綻すると思うけど。

中間にRabbitMQとかくっつけるのが正しい気がする。


エラー処理について

clientは、エラーが起こった瞬間subscribeをヤメて自沈する。

というかぶっちゃけredisについて詳しく知らないので、何がどうなってるのかコード追ったりしてみようと思う。


良く出来てるソフトウェアが多くて助かる。



とりあえず動かせたので

nginxのモジュール書くか、

コンセプトモデルだけこれでOKということにしてnginxを基礎にした別物をCでガンガン書くか、

何もかもなかったことにしてコンセプトをnginxから学びつつgoで遊ぶかの3択中。

ngx_lua、楽しいです。



wrote 2015/03/10 11:44:00

RUDPについて学ぶ


概要

興味が湧いたので学ぶ。

reliableUDP。


ギッハブから勉強になりそうなのを適当にピックアップして読むとかで、

動かしながら勉強。



C++,C,Obj-C

https://github.com/devekar/RUDP



C++

https://github.com/maidsafe/MaidSafe-RUDP



Python

https://github.com/kalasoo/rudp



Go

https://github.com/Bluek404/rudp



wrote 2015/03/09 23:45:04

2501の近況


概要

割と楽しくなってきた。

Push & framerateまでは達成できた。

適当にOrchestrationまで頑張る。



real time logging

c1, c2, c3 

―――――

| |

| GameServer

|

2501

c1~3 realtime logging



Push & framerate

2501

| push

| framerate 100f/sec

| context

|

―――――

c1, c2, c3



Orchestlation

2501

| command、macro

|

―――――

c1, c2, c3

―――――

|

GameServer



直近としては、redis依存とかをnginx側に手を入れることで解決したい。



wrote 2015/03/09 10:55:58

addとdeserializeが低コストなログ用の形式が欲しい、、欲しくない?


概要

まあ特殊なニーズなんですけど、ログを取るとき、追記可能でかつイザって時に

特定の言語向けにdeserializeできる形式が欲しい。



用途

例えば、ログ自体からオブジェクト作り出して、実行可能な情報として動作させたい。

んでその際、独自形式を作りたくない。



現状

tomlが一番欲しい物に近いかなって思っている。



例えばjsonでログを取る(この表現が既に狂気なのは承知してる)とかだと、

次のようなログになるとして、



log.json

[

    {

        "key1": "val1",

        "key2": "val2",

        "date": "2015/03/0819: 58: 39"

    }

]


で、


追記するためには、とじカッコとかその辺がクソみたいな感じで邪魔になる。


log.json

[

    {

        "key1": "val1",

        "key2": "val2",

        "date": "2015/03/0819: 58: 39"

    },

    {

        "key1": "val1",

        "key2": "val2",

        "date": "2015/03/0820: 00: 23"

    }

]


濃い部分が追記された内容。

単純に改行 + α、、みたいな感じにはならない。

正しくやるには、

original -> parse -> add -> serialize


みたいな行程を経ないといけない。

こんなことでっかくなりつづけるファイルに対してやってられない。


original -> add 


だけで済み、かつdeserializeできる形式が欲しい。



tomlさん出番です

そのへんtomlさんは凄い。できる子。


log.toml

[identity]

date = "2015/03/0819: 58: 39"

key1 = "val1"

key2 = "val2"


追記するとして


log.toml

[identity]

date = "2015/03/0819: 58: 39"

key1 = "val1"

key2 = "val2"

[identity2]

date = "2015/03/0820: 00: 23"

key1 = "val1"

key2 = "val2"


とかにできる。

まあ書き込みがアトム~な感じじゃないと成立しないのはどっちも一緒。


identityに関しては、同じ対象であれば同じ値を使う、とかすると、deserialize時に折り畳まれる。時系列に並べたければ主キーをdate or 何かにすればいいのではという感じ。

逆に、deserializeでshrinkされること自体が特性っちゃあ特性で、


時間を適当なインターバルでゾーン分けすると、特定のタイムスパンで起きた出来事を一気に見やすくできる。

こんな感じ。


[datezone]

    [datezone.id1]

    date = "2015/03/0820: 00: 23"

    key1 = "val1"

    key2 = "val2"

[datezone]

    [datezone.id2]

    date = "2015/03/0820: 00: 49"

    key1 = "val1"

    key2 = "val2"


datezoneは適当な[1分間以内に発生した物事の区分]とかにしたと仮定する。

これはjsonだと下記と=になる。


{

  "datezone": {

    "id1": {

      "date": "2015/03/0820: 00: 23",

      "key1": "val1",

      "key2": "val2"

    },

    "id2": {

      "date": "2015/03/0820: 00: 23",

      "key1": "val1",

      "key2": "val2"

    }

  }

}


書き込みやすさと情報量に対して、一気に差がつく感じ。



どこかにメモっておきたかった。

wrote 2015/03/08 0:33:36

Unity Editor のupdate callbackがYosemiteで減速する現象に勝つ


概要

Mac OS 10.10 Yosemiteでまじめに頑張ってこなかったので気づくのが遅れたが、

条件を満たすとUnity Editor のupdate callback の呼ばれる頻度や、

それ以外のtimer系のThread挙動も軒並みヘタレていくのの原因と解消法が分かったので書く。


まず間違いなく俺以外困ってないはず。



トリガー

次の条件を満たすと、だんだんUnity Editorのあらゆるタイマー的な動作がスローダウンしていく。

・Unity Editor をGUIありで起動中

・フォーカスをUnity Editor以外にあてる

・時間経過(20秒以上経過)


スローダウンの具体的な内容

以下のようなことが起きる。

・Editorの update callback が100回/秒なのが1回/秒まで減速、ヘタレる

・自発的にセットした0.1秒に1回のTimerThreadとかも例外ではなくヘタレる



回復手段

Unity Editor にフォーカスを当てると戻る。

が、フォーカスを離すとまた減速する。



原因と回避手段

OS X 10.9 Mavericksから追加された機能 App Nap が、Yosemiteになって凶悪になっていたのが原因。

OS X 10.9 時はフォーカス外しただけだとApp Napの発動条件を満たすことはなかったようなのだが、

OS X 10.10 以降はフォーカス外すと即App Nap対象になるようだ。

アプリケーションがApp Nap状態に入ると、どんな動作条件を決めたものであろうとひたすら減速するようだ。

回避方法はメッチャ単純で、App Napになってほしくないアプリケーション.app > 情報を見る > App Napを切にする でおわり。

スクリーンショット 2015-03-04 3.31.32.png


はい。


こんなよくわかんないIssueにつきあってくれたUnity Japanの方、どうもありがとうございました。




wrote 2015/03/04 3:18:23

lua-resty-websocket使ってみてる


概要

これ

https://github.com/openresty/lua-resty-websocket

resty込みで使うんなら的な解説

https://medium.com/technology-and-programming/websockets-with-openresty-1778601c9e05



Install

書いてあった。備えあれば嬉しいな的。

https://github.com/openresty/lua-resty-websocket#installation


nginxで受けたら即WebSocket接続できるぞ~わーい!

簡単な実装を下記で作り中。

そのうち2501と混ぜる。

https://github.com/sassembla/nginx-luajit

wrote 2015/03/01 13:37:24

座駆動LT大会2015Spring


概要

麺 + Jenkins

麺のFutureをみせてやろう、、!!



死霊

https://dl.dropboxusercontent.com/u/36583594/outsource/Menkins.pdf


wrote 2015/02/27 13:51:39

nginxでLua使ってみる話私的まとめ


概要

nginx lua使ってあそぶ。

といいつつ、luaでのコンテキストをWebSocket越えさせる目的がある。


死霊

Using ngx_lua / lua-nginx-module in pixiv

http://www.slideshare.net/harukayon/ngx-lua-public


lua-nginx-module を使いこなす

http://qiita.com/kz_takatsu/items/e94805a8e3cc285f9b33


Nginx で HTTP API 化

http://qiita.com/Hexa/items/cb762d70a741bcc57498


nginx + lua-nginx-module の環境構築

http://qiita.com/futoase/items/4185432667569b6b3f35


OpenResty (nginx + lua) 逆引きメモ

http://qiita.com/voluntas/items/e86f5fe5b8044c311583



lua_nginx module

こんなの。

https://github.com/openresty/lua-nginx-module



ビルド

欲しいのはluaが実行できてあとあとオレオレエンジンとしてコンパイル可能にするコマンドラインツールとしてのnginxなので、いろいろDLして、そろえる。

依存を最小限にするためにRestyそれ自体の使用はしないことを考えている。

あとであっさり言ってること変わるかもしれない。

というわけでコレクション。


nginx 1.7.10

http://nginx.org/download


LuaJIT-2.1

cloneして2.1ブランチに切り替えて動かす。

git clone http://luajit.org/git/luajit-2.0.git

んだけど、makeしてもlibとか作られないのか、どうすりゃ良いんだろう。

とりあえず2.0.3をbrewで入れて、そこに入っているlibを使う。nginxの設定ファイルは下記


lua-nginx-module

https://github.com/openresty/lua-nginx-module/releases/tag/v0.9.15

ngx_devel_kit

https://github.com/simpl/ngx_devel_kit/releases/tag/v0.2.19


パラメータ設定してnginxをビルド

luajit 2.1のlibはあとで作る。


build.sh

export LUAJIT_LIB=/usr/local/Cellar/luajit/2.0.3_1/lib

export LUAJIT_INC=/usr/local/Cellar/luajit/2.0.3_1/include/luajit-2.0


NGX_DEVEL_KIT="ngx_devel_kit-0.2.19"

LUA_NGX_MOD="lua-nginx-module-0.9.15"


# Here we assume Nginx is to be installed under /opt/nginx/.

./configure --prefix=/Users/illusionismine/Desktop/nginx-luajit/b \

--with-ld-opt='-Wl,-rpath,$LUAJIT_LIB' \

--add-module=$NGX_DEVEL_KIT \

--add-module=$LUA_NGX_MOD


make -j2

make install


で、実行すると、

sh build.sh


無事sbin/nginx が出来た。

実行してみると、Welcome画面でたのでOK。



実行とテスト

OpenRestyのCLIのやつでサクサクに、、、と思ったのだけれど、

自分の用途だとSublimeでのコード編集/ビルド時にcurlぶったたくほうが楽だったので、次のスクリプトを書いて終わった。


コード保存したりビルドするたびにcurlが走るだけ。状態持ってないからまだ後悔してない。


luaFire.sublime-build

{

"shell_cmd": "curl http://localhost/lua-test"

}



実行結果はコードの下の方に出る

スクリーンショット 2015-03-01 13.02.19.png

お楽しみはここからだ

luaコンテキストを送信し合うのに興味がある。



wrote 2015/02/27 13:46:32

プロジェクト 2501


概要

忙しかった山が一段落 + 趣味も安定稼動したので、

そうだ、人形使いつくろう! みたいな感じ。


複数クライアントでのデバッグと操作介入のツールを作ることにした。


これ。

2501

https://github.com/sassembla/2501


モチベーション is 何

・別のゲームに接続しているClient群の監視、制御を行う

・デバッグ、ゲームサーバからは独立した、Client依存のbotづくり



目的と手段

・内包しているnginxでClient群からのWebSocketを受け、だいたいリアルタイムでClient群についてログる

・接続しているClientへのコマンド代入を行う

(nginxでlua動かして、virtualClientからのコマンドをWebSocket経由でクライアントに送る)


これができると、また別の意味でのOrchestrationが出来るようになると思う。Orchestration言いたいだけ。

あと個人的に遊びでlua使いたい。


リアルタイムログもClientOrchestrationも

本来ゲームサービス側が保持すべき性能なんだけど、なかなか実際の仕事でゲームサーバ側がリアルタイムログ集計、コマンド仮送りをするのが難しい。



リアルタイムログ集計

ほとんどのゲームは、動作するのに必要以上のリアルタイムログを必要としない。つまりゲーム本来の目的とは合わない。


ただ単に、サービスが求めるリアルタイム性みたいなのと関係ないデータをゲームサーバに送りつづけることそれ自体が不効率だ。

なのでどっか別のところでリアルタイムに見れるように出来れば面倒さが無い。



コマンド代入

先月?のJenkins Confで少し話していたのだけど、ゲームの自動プレイを行う領域をどこに持つべきか、って話で、

サーバからOrchestrationできればいいのにねーって話していたが

・Client-Server間で進捗が別途であること

・Clientの状態が存在することを考えるとサーバ側が後手に回らざるをえないこと

とかを加味すると、現実的ではない感じがした。


ので、

・Clientに直結

・Clientが受け入れ可能な状態とシンクロしたコンテキストを持つ

という前提で動くものを作ってみたくなった。


コンテキストまでどうシンクロさせるのか、とかは考え中。


Why WebSocket

ブラウザにも繋ぐ事が出来る。



現在

WebSocketServerをUnityで試作した。

Application寄りすぎて使いづらいので、nginxとか内包する感じで再設計する。


wrote 2015/02/26 0:57:13

Mac VMを飼うガイド


概要

みんな大好きこれからは廃れるっぽい存在 仮想環境で、

Mac OS X Yosemite VM をMac OS Xの中に作ろうぜみたいなのやってたので纏める。



前提となる環境

OS X Yosemiteが入ってるMacマシンに、Yosemite VM を2台入れるような感じ。

VMを2台以上飼う場合は、Mac OS X のライセンスが別途必要になるはず。



VMの飼育環境を整える


VMの動作環境として、VirtualBoxをインストール。

virtualbox

https://www.virtualbox.org/wiki/Downloads


YosemiteのインストーラをMac AppStoreからDL。

[Install OS X Yosemite.app] てやつ。


Yosemite VM 用のディスクイメージを作り出す

以下の3から先を実施


Install OS X 10.10 Yosemite in VirtualBox

https://gist.github.com/frdmn/de12c894a385bc8e6bff



VMを作成するまえにVirtualBoxで成すべき事

ホストオンリーアダプタを必要な個数だけ作成すること。

VirtualBox > 環境設定 > ネットワーク > ホストオンリーネットワーク を、今後作るVMの数だけ作成しておく。

緑のボタン押すと、vboxnet0 みたいな名前でアダプターが作られるはず。

 ss.png



で、内部設定はこんな感じ。作成されたタイミングでユニークなので、いじらないでOK。

 scr.png


scr2.png



VMが作成用意できたら起動前に速攻でやるべきこと

・起動前に、VirtualBox > 作成したVMの設定 > ネットワーク > アダプター2 の割り当てに、ホストオンリーアダプターを指定。

・名前のとこからvboxnet0とかを選ぶ。

 host.png



VM起動時に発生するトラブルシュート

Install OS X 10.10 Yosemite in VirtualBox

https://gist.github.com/frdmn/de12c894a385bc8e6bff


に、Missing Bluetooth Controller Transport->対策が描いてあるので対応。

VirtualBoxGUIからYosemite VMを完全停止して、


VBoxManage modifyvm ‘YosemiteVM’ --cpuidset 1 000206a7 02100800 1fbae3bf bfebfbff

を実行。


VM起動後の設定

起動完了したら以下を行う。


・システム環境設定 > ユーザーとグループ > ログインオプション > 自動ログインをOnに設定する。

homebrewほか、いろいろなところで困るので、空のパスワードを使ってはいけない。

ただし後述の問題が発生すると面倒くさいので、自動ログインはOKのほうが良いと思う。


・システム環境設定 > 共有 > リモートログイン をOnにする

・ホストのsshから入れる事を確認


ここまでくれば、VMに何があっても安心な感じになる。



注意点

GUIからログインできなくなることがある

文字通り、Yosemite VM のログインパスワードをいれても、ログインできなくなる。

具体的に言うと、パスワード入力後、レインボーが回りつづける。


GUI上でのみ発生するのを確認している。

対策としては、

ログイン画面を失くす。起動、即特定ユーザーでログインできる設定にするとか。


もし陥ってしまった場合の解消法としては、

・VMを起動、ログイン前の状態で放置

・ホストからsshでYosemite VMにログイン

・Terminal > passwd でパスワードを変更

・VMを再起動

・新しいパスワードを入れる

とやると、ログインが正常に完了するようになる。


つまりだ、自分はこれで九死に一生みたいな感じになった。



wrote 2015/02/24 16:01:10

UnityのPath.Combineの挙動で殺意駆動しよう


概要

UnityのPath.Combine関数の挙動がムカつく感じだったので纏めておく。

MacとWindowsで挙動が異なり、というかWindows版だけおもしろおかしい。


以下はすべてWindows版での挙動。



Path.Combine(string a, string b)

a,b2つのstrに対して、a/b のようにパスっぽく繋いで返す。


のだけど、例外的な動作が複数含まれている。



aの終わりが/である場合

var c = Path.Combine(“A/”, “B”);

cには A/B が入る。



aの終わりが/でない場合

var c = Path.Combine(“A”, “B”);

cには A\B が入る。エーバックスラッシュビィーだ。


で、当然のようにUnity内では、

Application.dataPath とかが


C:/somewhere/PROJECT_FOLDER/Assets


とか平然と/で区切ったパスを返してくるので、

ここでAssets下のパスとくっつけようとすると、


var c = Path.Combine(Application.dataPath, “folder/contents”);

c -> C:/somewhere/PROJECT_FOLDER/Assets\folder/contents


とかになる。\が混じる。苦痛だ。地獄か。

第一引数には/で終わるstrをいれないと、Mac/Win両方で動くコードにはならない。おま、、



例えばパスからファイルを読み込んだりする関数があると、こける。



Path.Combine以外にも\が混じるコードがあるようで、Mac/Winでそれらを大量に扱う場合、中間オブジェクトみたいなの用意して

Pathを扱った方が良い気がする。


間違っても/とか\を妄信的にpath delimiterとして使うと詰む。



bの始まりが/である場合

var c = Path.Combine(“A”, “/B”)

こいつは、/Bになる。A? 知らない子ですね、、、

C♯でのPath.Combine(str a, str b)の仕様もこうなので、「ヘェ~ふしぎだけどこういうものなんだな」以外の感想は無い。

きみらフツーはC:とかドライブ指定あるんちゃうんか。



以上から

第一引数の末尾が/か、 また、第二引数の頭が/ではないかどうか、調べて使うと事故が減る。

気に入らん。



wrote 2015/02/24 0:32:46

Realm Tech Talk with JP Simard 行ってきた


概要

素敵そうなモバイル用DB Realm(レルム)の話を聞きにいった。

これ。

http://realm.connpass.com/event/11815/

タグ #realm_jp

Realm is 何

モバイル用DB。

フルスクラッチ、完全新規なデータベース。SQLiteのラッパーではない。

4年かけてる。



フルスクラッチのモチベーション

サーバ側にはめっちゃ大量のDBエンジンが生まれているが、クライアント側には、、、

SQLiteから10年経っちゃったけど特にない。


CoreData、SQLiteのORMとしてはいいかんじだけど、、難しい、重い、遅い。

マルチプラットフォーム的に、Appleのモノなのでまあ、、はい、、


SQLiteを直に使う? できるけど、、、ORM的機能を求めていくとCore Dataに近づくだけ。

というかマジで機能が足りないしな、、


ほかにもいろいろな選択肢があるにはあるよな。


ベンチ

iPhone6での動作ベンチ。


insert

RealmはSQLiteより2倍遅いが、Obj-Cバインディング下なのでこの数値。

Realmの内部のC++部分をダイレクトにぶっ叩けばもっと速い。


count, query

Realmメッチャ速い。(x 2 SQLiteくらい)


高機能を保ちながら高速化するの頑張るよみたいな姿勢。



速さ

ディスクに対してのアクセスをもとにして速度を稼いでるっぽい。

メモリに乗っけない、ファイルに書く、というのを基礎にしている。

確かにサーバ上のDBと違って書き込む対象が絞られてる前提でこういう手段というか思い切りはアリだな~。

とにかくオンメモリに持たない、っていう手法。

(と思ったらon-memory-modeもあるらしい)



現在進行中のいろいろ

sync

デバイス間でiCloudみたいなシンクロができるようになる。

なにそれステキ。

→実装方法について詳しく聞く機会を得たので聞いてみたら、実装方法がメチャクチャファンキーだった。

・Webサービス、クライアントとUDPでデータやり取りしてサーバ上にデータをsync。

・オフラインでクライアント間の場合は、P2Pな感じでsync

ぉ、ぉぅ。


Webサービスまわりは野望が見え隠れするな。



coreのオープン化

まだバインディング部分(Java, Obj-C/Swift)がOpenになった形なので、コアも。



質疑応答

iOS側、Obj-Cっぽいメソッド名ってこのままなの?

→Swiftに書き替える形で名前変更中。

NSFetchResultみたいなものって用意されたりするの?

→groupedTableView ってサンプル見てくれみたいな

https://github.com/pietbrauer/CarthageRealmUploadFailureExample/tree/master/Carthage.checkout/realm-cocoa/examples/ios/objc/GroupedTableView


→通知に関しては、今頑張ってやってるぜ的。


なんでファイル直書きだと速いの?

→in-memory-optionもあるんだけど、説明しよう。

たとえばSQLiteだと、fetchとかでメモリ上にデータを読み出して、

その後Deserializeが行われ、、、ていう手間を経るが、

realmはそのへん省いているので速い。


速いベンチマーク見せてもらったけど、Realmが遅くなるケースってあるの?

→ある。

insertはSQLiteより遅い。

処理の部分的には、速いところがちょこちょこある。クエリ組み立てとか。

現在のシンプルさを保ったままもっと速くするように頑張っている。



wrote 2015/02/23 19:47:43

禅温泉


概要

小田原の回るおすしやさん 禅 のあとに、タクシーでコロナ温泉にいったら最高の感じでした。


例年だと禅でスタンド攻撃を食らった後、1.5km離れた駅まで死人のように歩いて記憶と体力をすべて失って解散、という流れでしたが、


ためしにタクシーで小田原コロナワールドの温泉に行ってみたら、

やはり記憶のすべては失いましたが、体力は初期値を上回って回復、ヤル気に満ちあふれるという状態が発生しました。

あとバグが直りました。


こちらからは以上です。



追記2015/02/22 19:36:54

ニホンゴに障害が残る副作用があるようで、ひどかった部分は修正しました。


wrote 2015/02/22 19:29:23

UnityのEditorのUpdateが走り出すのは具体的にいつからなのか


概要

Unityのエディタのなかで、Updateを使用したツールを作っていた際に気になったので調べた。

該当のAPIはこれ。


UnityEditor.EditorApplication.update

確認を行った環境は以下。

Mac OS 10.10, 10.9

Unity 4.3.7 ~ 5.0.0(beta) 



実行開始タイミング

最初のEditorのUpdateが走るのは、「InitializeOnLoad よりも後」だった。


InitializeOnLoad を付けておいたstaticクラスのコンパイルが終わり、動作が開始した際には、まだUpdateは走っていない。

InitializeOnLoad 内ではすでに走っているのかと思っていた。


公式の死霊に照らし合わせると、

http://docs.unity3d.com/412/Documentation/ScriptReference/index.Script_compilation_28Advanced29.html


Editor内でのコードのコンパイルが行われるのはコンパイル行程の最後、

1.Standard系がコンパイルされる

2.Standard Assets/Editor 系がコンパイルされる

3.Editor以外がコンパイルされる

4.Editorがコンパイルされる


の、4番よりもさらにあと、コンパイルが終わり、InitializeOnLoad が走っているタイミングでもまだ実行されていない。


たとえば InitializeOnLoad で処理を開始した場合、まだコンパイル行程が終わっておらず、ログにも「compile終わったわ~~」とか書かれていないので、

ああなるほどそういうこともあるんだなという感じ。


ちなみに最初のUpdateがはしるのは、ログでいうと下記の箇所だった。



IsUpdateRunning?:False

UnityEngine.Debug:Internal_Log(Int32, String, Object)

UnityEngine.Debug:Log(Object)

SublimeSocketClient:StartConnect() (at Assets/SublimeSocketAsset/Editor/Scripts/SublimeSocketClient.cs:442)

SublimeSocketClient:AutoConnect(String, String) (at Assets/SublimeSocketAsset/Editor/Scripts/SublimeSocketClient.cs:192)

SublimeSocketClient:Automate() (at Assets/SublimeSocketAsset/Editor/Scripts/SublimeSocketClient.cs:138)

UnityEditorEventHandler:.cctor() (at Assets/SublimeSocketAsset/Editor/Scripts/UnityEditorEventHandler.cs:13)

System.Runtime.CompilerServices.RuntimeHelpers:RunClassConstructor(IntPtr)

System.Runtime.CompilerServices.RuntimeHelpers:RunClassConstructor(RuntimeTypeHandle) (at /Users/builduser/buildslave/mono-runtime-and-classlibs/build/mcs/class/corlib/System.Runtime.CompilerServices/RuntimeHelpers.cs:101)

UnityEditor.EditorAssemblies:RunClassConstructors()

UnityEditor.EditorAssemblies:SetLoadedEditorAssemblies(Assembly[])

 

(Filename: Assets/SublimeSocketAsset/Editor/Scripts/SublimeSocketClient.cs Line: 442)


Requesting http://update.unity3d.com/4.3/ivy.xml

Downloading into /var/folders/8r/04ts4kp16yv700w9kdgzpqb80000gn/T/unity/50acea4d-04e3-42c3-8ab1-454a6ea089a9/ivy.xml


----- Total AssetImport time: 0.161818s, Asset Import: 0.000000s, CacheServerIntegrate: 0.000000s, CacheServer Download: 0.000000s [0 B, nan mb/s], CacheServer Hashing: 0.000304s [0.9 KB, 2.780007 mb/s]


Mono: successfully reloaded assembly

- Completed reload, in  1.966 seconds

first update!


太字のところに注目、

IsUpdateRunning?:False は InitializeOnLoad で着火しているメソッドの中でupdateにセットしたイベント内でのログ。

first update! が実際に初めてUpdateが走った箇所。


Completeのログが出るまでは、Updateは走らないぽい。


時系列でまとめると下記のような感じ。

・~ Editor Scriptのコンパイル完了、DLLのロード開始

・InitializeOnLoad Attributeがついてるメソッドの着火

・それらの完了

・正式なコンパイル完了

・Update起動開始

は~~~Updateの特性を考えるとしょうがないのか。

例えば複数の「Updateに依存するEditorScript」があった場合、Updateが走り出したタイミングでDLLのロードが終わっていないと

相互依存できなくなったりカオスになったりでメチャクチャ困るわけだ。


正直Updateが走り出してからInitializeOnLoadが走ってくれると嬉しかった。

というかその場合は、Updateが走り出してから走らせるようにすればまあそれでいいんだな。


最初のUpdateで一度だけ走って消えるようなハンドラでいいよね。



UniRxを使ってエディタでのスクリプトを書く場合

ちなみに便利で素敵なUniRxを使ってEditorのコードを書く場合、

UniRx

https://github.com/neuecc/UniRx


http://u3d.as/content/neuecc/uni-rx-reactive-extensions-for-unity/7tT


UniRxがエディタ上でCoroutineとか回すのに使っているのは上記の EditorApplication.update なので、

initializeOnLoad 中のメソッドでセットしたりStartCoroutineしようとしても、即着火はしない。

実際にはInitializeOnLoad のブロックが終了したあとになってはじめてコンパイル完了のタイミングを迎え、

Updateも走るようになるので、そこで初めて着火する。


というかUniRxの挙動のおかげで、Updateの開始位置をまともに調べるに至った。

勉強になった。



おまけ:Updateが、、、死んでる、、、!?? っていう地獄のような話

とあるユーザーさんからのご連絡で判明したんだけど、

Updateに依存したコードを書いてて、着火しない、っていう事態があったそうな。


状況を聞いた限りだと、

・Mac版Unityで発生(Winで起きるかはしらない)

・UnityEditorを起動、プロジェクトを開いているのをチラ見したあと、UnityEditor以外のアプリケーションをアクティブにしていた

・バックグラウンドでコンパイルが完了するのを目視

っていう状態で、EditorApplication.update が一回も発生しない、という状態が発生したとのこと。


んでじゃあ再現してみるべ、って試してみたら、下記手順で再現できた。


1.MonoDevelopとかエディタでコードを書く

2.保存

3.コンパイルさせるためにUnityEditorをActiveにする(ウインドウとかをマウスクリックするだけでOK)

4.MonoDevelopとかエディタにもどる(ウインドウとかをマウスクリックするだけでOK)


1~4を高速で行うと、コンパイル完了してもUpdateが発生しない場合がある。

試したところで20回に一回くらいだった。

すげー頑張った。



確かにコンパイル完了してるはずなんだけど、Updateが一度も走らない。


ちなみに心配になってFocusしにいくとUpdateは元気に走り出す。



推察するに、Unityにフォーカスが移った時、2段階以上の予備動作時間があるみたいだ。


0.focus ->

1.コンパイル開始の条件を満たす ->

2.stay focus ->

3.Updateが走り出すための条件を満たす


みたいな。



日照時間みたいなものかな、、、



3の条件を満たす時間的な要因はよくわかっていない。

あとたぶんハンドラとかも無いと思う。


あ、ログに何か出るとかはあるかもしれない、、し、無いかもしれない。



あれか。

君はじっと眺めてないと働かない子か。まあいいんだが。



ちなみにコンパイル時間 = プロジェクト規模との相関は不明。

あと、コマンドラインから起動した場合はどうなっちゃうんだ?

AssetRailsでも利用してないから気にはなる。


というわけで、日照時間が極端に短いと、コンパイル完了後にUpdateが走り出さないという事象を確認した。


Unity氏~~~~ もうめんどうくさいからコンパイル開始APIくだされ~~~~




wrote 2015/02/14 20:46:15

AssetStoreに出してる奴の無料サンプル祭り


概要

AssetRailsに関してはまだ審査通ってもいないので何してんのって感じだが、

最近海賊版的な感じで無料DLできたりするのもあるし、

無料サンプル作る手を思いついたので、暇に飽かせてやる。


今後会社のやつも足すかもしれない。とりあえず完全自作のみ。



SublimeSocketAsset for Free

市場にでてるのがver 1.8.x なんだけどいろいろあってver 2.0系になったぞヒャッホウ!


フリー版置いた。

https://github.com/sassembla/SublimeSocketAsset-support


の中の、

https://github.com/sassembla/SublimeSocketAsset-support/tree/master/Assets/SublimeSocketAsset


フリー版としての機能は、

・エラーがコード上に表示される

・Debug.Log(“L:” + なにか) が時系列でコード上に表示される

・UnityEngineのクラスは補完可能

・リアルタイムでの構文解析エラー見れる(new!)

・保存でコンパイル着火可能


自前でOmni Sharp使う設定をするめんどうくささを我慢できるならそれはそれでいいんでは。


AssetRails for Free

フリー版置いた。

https://github.com/sassembla/AssetRails-Support/

の中の、

https://github.com/sassembla/AssetRails-Support/tree/master/Samples/Sample_AssetRails


フリー版としての機能は、

・固定ルート、固定パラメータ

・import -> prefabricate -> bundlize -> versioning 限定

・Runner書き換えでimportとかの処理内容を変えられる

・AssetBundle作れるのがWebPlayer限定

・toml使用不可(experimentalだしな)

wrote 2015/02/10 14:15:10

AssetRails ~素材読み込みからAssetBundle作りまで、commandlineで~


概要

AssetStoreへと申請してしました。純粋な個人作では第二弾。


AssetRails

~審査中~

AssetRails-Support & Sample

https://github.com/sassembla/AssetRails-Support#assetrails-overview



使ってみたい人がいたらTwitterで@sassemblaまで連絡をくれ。

実験体になってくれ。



ニーズ

以下がやりたかった/二度とやりたくなかったので作った。

・1~2個とはいえGUIで設定するの面倒くさい

・素材をUnityにインポートするところから圧縮まで、作業のフェーズ分け

・まともさをもった再利用ビリティ

・どこで失敗したかの明示

・途中リソースの利用(このへんドキュメントに書き忘れたな?)

・追加リソースの作成自動化と、過去リソースとのマージ、デプロイ前までの整理


などで、今後盛大に自分のためになってくれると思う。



素材をUnityにインポートするところから圧縮まで、作業のフェーズ分けを行った

Unityでの各種リソースの扱いは、元からかなりラクだと思うんだけど、

反復とか量をさばいたり、またそのファイル変化の種類も多岐にわたるので、


読み込みからの処理を、大きくインポート(import)プレファブリケート(Prefabricate, 組み立て)に分けた。

そこにさらに、AssetBundleや独自処理でのbundle化を行う行程(bundlize)を定義して、

最後にbundle後のファイルをバージョン管理する行程(versioning)を設けてある。


で、それらをcommandlineから個別に実行、反復させることができるようにした。



行程(route)とピッタリなブラウザインターフェース


たとえばimportだと、

コード的に、Unityに素材を読み込んだときに走る処理の内容とかを書きやすく、再利用しやすくした。

具体的には、クラス定義、パラメータ追加がしてあって、こんな感じに書ける。


public class SampleAssetRailsBasedImporter : AssetRails.ImporterBase {


public override void AssetRailsOnPreprocessTexture () {

// Debug.Log("Import:categoryName:" + categoryName);

// Debug.Log("Import:bundleName:" + bundleName);


// run import settings for specific category.

if (categoryName == "characters") {

UnityEditor.TextureImporter importer = assetImporter as UnityEditor.TextureImporter;


importer.textureType = UnityEditor.TextureImporterType.Image;

importer.textureFormat = TextureImporterFormat.ARGB16;

}


if (categoryName == "images") {

UnityEditor.TextureImporter importer = assetImporter as UnityEditor.TextureImporter;


importer.textureType = UnityEditor.TextureImporterType.Advanced;

importer.npotScale = TextureImporterNPOTScale.None;

importer.isReadable = true;

importer.alphaIsTransparency = true;

importer.mipmapEnabled = false;

importer.wrapMode = TextureWrapMode.Repeat;

importer.filterMode = FilterMode.Bilinear;

importer.textureFormat = TextureImporterFormat.ARGB16;

return;

}

}

}


☆categoryName, bundleNameは下の方の「前提」のズを見れば、何されてるかわかると思う。



また、どこまで動いてんだよ的な把握ができるように、Viewを持たせた。

webInterface.png

\\ パーセンテージでわかるの最高やぞ //

('ω' )三('ω')三( 'ω')"



前提

下記のようなフォルダ構造を切った。下記のような構造でファイルを置いておけば、あとはAssetRailsが適当にやってくれる。

overview.png



Unity5と被ったところ

version管理まわりで、versionedList.json ってのを書き出しているが、その内容はUnity5の吐き出すあれとほぼ被った。

ただ、commandline前提で全部組まれたものは見た事無いので、たぶん俺が勝つ(嘘)。



いや~importとかから自動化する前提で組みたいんだよ。なのでGUIでなにかするのはパスだ。

エクセルとかで管理した素材フォルダさえあれば動く、っていうのが理想だと思っているので。


Script動作を排してないので、動作互換あるから、まあつかってみてよって感じ。



圧倒的オリジナリティ

コマンドラインでチマチマ実行してもいいんだけど、

jsontomlで書いたrouteをまとめて実行、っていうのもできる。


こんなかんじの書き方のjsonを実行したりできる。

[

    {

        "clean": {}

    },

    {

        "setup": {

            "--work-platform": "StandaloneOSXIntel"

        }

    },

    {

        "import": {

            "--dryrun": false,

            "--info": true

        }

    },

    {

        "prefabricate": {

            "-i": true

        }

    },

    {

        "bundlize": {

            "-i": true,

            “--actual-size”: true,// compressedでも実際のサイズがわかるようになる感じ

            "--fast": true

        }

    },

    {

        "versioning": {

            "-i": true,

            "--version": 1,

            "--platform": "iPhone",

            "--crc": true

        }

    },

    {

        "versioning": {

            "-i": true,

            "-v": 1,

            "-p": "WebPlayer",

            "-c": false

        }

    },

]

tomlまだexperimentalだけど。


がんばりたくないひとにオススメ。



体験版

そのうち作る。

あ、いいサンプル思いついた。レールの内容固定でlibにしてサンプル作ればいいんだ。

ってこの手は結構使えそうな気がする。




wrote 2015/02/09 13:49:55

いまさら書けないAssetBundleのcache周りの知見


概要

UnityのAssetBundleをcacheする機構について、以前悩んでたことがあったんだけど、

最近人に聞かれて「ああ~~そういえば」ってなったので書いておく。

Uni本2の内容でコラム欄とかに書いた気でいたんだけど、時間無くて脱落させたままだった。

Unityのひとに聞いて裏付けがてら列挙する。

AssetStoreへのアップ用に使っているUnity4.3.7p4の挙動がベースなので、まあなんだ、古いこと書いてるかもしれない。



新versionのAssetBundleを入れても旧versionのAssetBundleは消えない


WWW.LoadFromCacheOrDownload(url, version, crc)

このメソッドの話で、

新しいAssetBundleを作成、versionに新しい値を希望いっぱいで入れたとする。

古いAssetBundleはどうなるか?



消えん。直感に反する感じする。



たとえばあるAssetBundleを version:1 として読み込んでおいたあと、

同じidentityのAssetBundleを version:2 として読み込むと、

version 1、2ともにキャッシュに残る。やったぜ!



?????ってならない? 俺はなった。

実際のアプリケーションのサイズを観測したらまあ確かに。増えていた。



ただドキュメントのどこを見ても、「cacheからAssetBundleが消える条件」ってのに

「versionが違うのを取得したら古いのは消える」って書いてないので、はい。

厳密に言うと、versionが上がったら、ではなく、cacheされているのと違ったら、なので、

たとえばまあ、1, 100, 200 みたいな書き方でいろんな、同じ名前のAssetBundleをcacheさせる事も可能な訳だ。


、、、、

、、

俺はやらないけど。そんな、、なんか、、アレなこと、、


「だったらversionって名前じゃなくてindexとかidとかにすれば良かったのでは?」と思わなくもない。


とりあえず現状でのcacheの実装はそういうものなので、まあなんだ、アレだ、アレ。

version値は固定でいいんじゃないかな。



削除について

AssetBudnleがcacheから消えて行くときは以下のようなルール。


・許可されてる最大cache量(Caching.maximumAvailableDiskSpace)をリミットとして、それを超えそうになると消えていく

・最終参照日時(タイムスタンプ)が古いものから先に消えて行く

・version 1, 2 で1のほうが参照されたタイムスタンプが新しい場合、2のほうが消される順が速い

このへんを正当っぽい感じで利用して、

Caching.maximumAvailableDiskSpace を指定することで、ある程度自動的にcacheのサイジングをするのもアリだと思う。

具体的には、以下を行う。

・新規取得するAssetBundleと、残したいAssetBundleを把握できるようにする

・残したいAssetBundleに参照マークを付ける

・新規取得するAssetBundleの展開後サイズと、残したいAssetBundleの解凍後サイズを合算した値をCaching.maximumAvailableDiskSpaceにセット(ムズイ)


これで、

新規をDLすれば、最近参照マークがついていない(= 最終参照が古い)ものからゴウンゴウン消えて行く。


誤ったcrcを指定して古い( = 使わなくなったので消したい)AssetBundleを消す、っていう方法もあるけど、

想像する動作構造的に大変なんだかなぁ感があるのでこう、はい。

ここで想像してる動作としては、

・versionが合っててcrcが合ってない -> 

urlへと同一のidentityを持つAssetBudleを取得しにいく -> (この時点で保持していたAssetBundleを消しているのでは?と思ってる。)

同じidentityのAssetBundleがあったので取得してcache

or

同じidentityのAssetBundleがなんか取得できなかったけどまあいいかでFinish エラーが出る


みたいなの。取得結果を待たずcache消すのファンキーだなあ、ハハハまさかなハハハ。


公式の中の人にこの消し方の話をすると、100%「いや、、あれは、、現状の結果として消えてるだけなんで、、頼るのは、、危険、、、」みたいなお話をしてくれるので、

なんだ、アレだ、この削除方法に頼らない方が良いと思う。


対して、Maxサイズ指定の心太式を用意しておくと、まあ自動的になるのでラクかなという感じはする。

少なくともユーザーを殺さなくてすみそうだ。


あるとうれしい機構としては、重量制限はセットすべき物、として制約をかけることができ、

制約に触れると「アラート出してStreamが流れてくる”親分、この古いやつらどうしやす!?”みたいな問いかけをしてくるメソッドが呼ばれる」

というのがUnityに積まれるのを期待している。


フォルダ単位の監視だったらわりかし簡単に作れると思うけど、その手のフォルダを実機内でハンドルする機構を自分で作るの厭なんだよね。



同一のAssetBundleの更新はラク

さっき紹介したのは削除テクニックではなく、根本的には更新のためのテクニックなので、

その正しい使い方もメモしておく。


同じversionでcrcが異なるものを指定した場合で対象のAssetBundleのcacheを更新できる ので、

更新であればversionを上げずに(versionというパラメータ名がメッチャ直感に反するが)奇麗にキャッシュから古いのを削除、更新されたものを取得、上書き、っていうのができる。

仕様的に、AssetBundleの一意性はAssetBundleの名前(ファイルに埋め込み)で行われていて、

URLがどうなっていようと手に入ったAssetBundle自体のデータで一意性を決めているので、


WWW.LoadFromCacheOrDownload(url1, version, crc1)


で、結局はDL後に取得したAssetBundleのIdentityから「同じAssetBundleかどうか」の判断が行われている。

(version部分で多層的になることはあり得るが。)


で、ただ単に同じAssetBundleを更新したい場合、


WWW.LoadFromCacheOrDownload(url2, 1, crc2)


って書き方で、version値は固定の1、だがcrcが違うはずなので、cacheされているAssetBundleの破棄、取得、cache更新が発生する。

versionって名前付けた奴出てこい、みたいな気分になるが。


更新するのであればこれだけでよくて、なんというかまあ、

使わなくなったAssetBundleの削除に関する事象が大変だなぁという懸念のみが残る。



AssetBundleがいつ展開状態になるか

AssetBundleがDLされ、cacheされ、いつ「Bundle化が解かれるか」みたいな話。

このへんは、App内でAssetBundleが いつから、どんな状態で保持されているか、というのと関わってくる。

BuildAssetBundleOptions.UncompressedAssetBundle を指定しなかった場合、

AssetBundleは、

DLが終わるまでは圧縮された状態で扱われ、

実端末でのAppの内部では、「AssetBundleファイルの状態から、別形式に展開された状態」で保持されている。


AssetBundleのサイズと、実際の端末内での容量の減り方から確認した。


AssetBundle化の効果であるファイルのがっちゃんこ + 圧縮処理によって、

「AssetBundleの元になっているAsset郡のサイズ合計 > AssetBundleのサイズ」

みたいな関係になっているのだが、


App内にDLしたあとに端末の空き容量が予想以上にドカッとが減るので、「ああ、展開して保持してるんだな」という感じ。


DLサイズ = AssetBundleのサイズ なんだけど、保持サイズ = 展開後のサイズ という。

つまり、AssetBundleのサイズとDL後のサイズには関係がない。

この辺、展開後のAssetBundleのサイズを取得するAPIってあったっけな、、無かった気がするな、、(手元でいっぺん開けてサイズを見ればいいのでは、という投げやりな感じ)


なんでこんなの気にするの?っていうと、

この展開後のサイズこそ、Appの重量に直結するし、Caching.maximumAvailableDiskSpaceが計算に使っているパラメータだから。


まあそんなこんなで、BuildAssetBundleOptions.UncompressedAssetBundle を指定しない場合、AssetBundleになった際のサイズを測っても意味は無い。


さらに言うと、AssetBundleは作り出すたびにidentity以外のパラメータが変動するので(作成日時とか入ってるんじゃねーかな)、

もちろんサイズも変動しちゃうので、正確なサイズを出すにはAPIの助けか、展開後のサイズをメモっておく必要がある。



AssetBundleの実機内でのサイズについて

ちなみに、Unity Editor上で特定のプラットフォーム向けにAssetBundleを作り、cacheした状態のファイルは、Macだと以下の場所にstoreされる。

/Users/USER_NAME/Library/Caches/Unity/


で、そこに出てくるファイルはすでにBuildAssetBundleOptions.UncompressedAssetBundle指定無しで作成したAssetBundleだった時のサイズとは異なっている。

圧縮状態からの展開済みって感じのサイズ。ただしファイル数はまだ1つの状態。

スクリーンショット 2015-02-05 1.33.14.png

PROJECT_NAME/フォルダ/AssetBundle(圧縮解除後) という並びになっている。


AssetBundleのidentityごとにフォルダが作られる、って訳ではなく、

AssetBundleのidentity x version の組み合わせで、同じAssetBundleなんだけどversion分だけファンキーな感じでフォルダが作られる。



versionの意味を勘違いして1,2,,みたいに上書きするつもりでAssetBundleをキャッシュして読み込むと、ここのフォルダが無限に増えていく。



で、内容のファイル名もidみたいな感じなんだけど(上記でいうCAB-863e4~ っていう名前のファイル)、

Finder上と、実際のcache後に取得できる解凍済みAssetBundleのサイズに差がある。


Caching.spaceOccupiedの値をみる限り、端末内のcacheを食う量はわずかに増える傾向にある。というかドンピシャで53byte増える。


プラットフォームやバージョン、比較対象ごとに違う可能性があるが、

Unity4.3だと、Finderで確認できるAssetBundleのサイズと、cacheを走らせたタイミングでのCaching.spaceOccupiedの値を比べて、+53byteのサイズ差がでた。

cache時にCaching.spaceOccupiedで吐かれる値が + 53byteでかい。


この53byte、Mac上だと、ちょうど同じフォルダにある__infoってファイルのサイズと一致するんで、

Caching.spaceOccupiedは、__info を含めた、このフォルダ全体の重さを計ってる感じ。


ちなみにiOS上で計ってみたところ、機種差があるかどうかはわからないが、+53byteで同じ結果がでた。

__infoファイルが作られてるんだろうなあきっとという感じ。



ところでAssetBundleは作り直すたびに違うサイズになる

上記でも触れたけどそういう感じ。

内容は一緒でも、作り直すたびにサイズが変化(誤差レベルだけど確実な変化)、もちろんcrcも変化する。

ただしcache後のサイズは変わらない。構成要素が一緒なんだからまあそう。



感想

デフォルトで存在するAPIとしては、AssetBundleは魅力的なんだけど、

ゲームの要件にそぐわない感じでなければ使いたいなあ。


デフォルトで入ってるので。


こういうところであんまり頑張りたくない。




こちらからは以上です。

wrote 2015/02/04 12:47:46

Markdown書くツール探して彷徨った10分


概要

Mouが、2015/02/01 17:01:10 DLできるversionだと常に最前面にWindowが出る状態になってて、実用に堪えなかったので投げ捨てた。


で次にplanB、AtomさんでMarkdo,,w,,,n,,,

辛い。


具体的に言うと複数ファイル開けるのに別のファイルにフォーカス切り替えてもmarkdown側は切り替わらないしファイル境界の移動(左右ビューの比率変更)とかも出来ないのでハッハッハかなぐり捨てンぞ


というわけで探してみつけたこれが良かった。

MacDown

http://macdown.uranusjr.com



そんなMacDown

スクリーンショット 2015-02-01 16.59.40.png

10分つかったあたりでのMouとの差分は以下


無駄に最前面に来ない

ハイ


“(ダブルクォート)などが自動で閉じない

Mouだと文字囲みになる、とじまで自動入力してくれるんだけどイマイチ頭がわるい挙動をしていたんだけど、

MacDownだとそれはない。


まあ無くてもいいや。



選択範囲へのB(強調)とかは普通に動作

文句無いです。



こちらからは以上です。


wrote 2015/02/01 17:07:04

VMとしてYosemite複数台飼ってて見舞われるトラブルと対処


概要

VirtualBoxを使って、Mac OSのライセンス的なものをクリアした上で、

ハイパ~なマシン上で複数台のMac OSを飼育していて、

こまったことがあったのでメモ。



GUIでのVMログインに失敗する

症例:

ログインに失敗するケースがある。

症例としては、VM起動 -> パスワードを入れたあと、レインボーアイコンが回り続けて数年が経過しそうな感じになる。


時間が解決する物ではなく、一度発生すると頻発するようになる。

原因は、VirturlBox上だとログイン時のキーチェーンへのアクセスでエラーが出るためっぽい。

まあノーサポートだし。



解決法:

解決法としては、エラーがでているキーチェーンへのアクセス箇所をなんとか避けるように手を加えてみればよかった。

具体的には、パスワードを変え、ログイン直後のキーチェーンアクセスへのアクセス方法が変わるように調整する。

sshからVMにログインし、パスワードを変更、VMを起動しなおしパスワード(変更後)をいれることで、

キーチェーンが知っている従来のパスワードからの変更に対するお問い合わせ操作が発生する。

このとき、

「パスワード変更したね、キーチェーンはそのへんどうしたらいい?」

っていう画面を出すことで、キーチェーンへのアクセスの内容を上書きすることができ、結果的に起動できる。


手順:

1.sshでHostからGuest(対象のVM)へのログイン後、passwd でパスワード変更

2.logout

3.VM再起動

4.新規パスワードを入力

5.keychainが「俺が知ってるパスワードから変更が行われたんだけどどうすればいい?」 って聞いてくるので新しいパスワードを入力

6.GUIでのログインが成功



追記していく。


はやくコンテナ化がすすむといいなと思った。

wrote 2015/01/26 18:32:08

UnityがPlayMode起動中かどうかをメインスレッド外から見分ける方法


概要

メインスレッドだろうと、UnityがPlayMode起動中かどうかは判断できない(compile中なのでisCompilingにはなる)ので、

わりと有益な感じ。

マルチスレッドなエディタコードとかで効率化計ってて、PlayMode起動に入ったら即なにかを開始する、みたいなエディタコードで適応したい。



方法

プロジェクト内にUnityが特定のファイルを作り出すのを利用する。


PROJECT_FOLDER/Temp/__EditModeScene の有無でチェックができる。


プレイモードを起動 → 存在しない場合新規作成される

→ 存在する場合上書きする



Unity 4.6.1系で確認済み。

が、このデータは、「Unityがクラッシュした際に復旧する最後の手段」でもある。



参考:テラシュールウェア

Unityエディタのクラッシュ時に失われたシーン情報を復旧させる裏ワザ

http://tsubakit1.hateblo.jp/entry/2014/10/20/230851



つまり俺都合で勝手に消したりすると殺意の波動にやられる。



ので、消す訳にはいかず、タイムスタンプのみを切り出して別途保存する形で扱う。


・プレイモード or 単なるコンパイルが発生したあと、エディタ側コードの起動が発生する

・起動後、適当なタイミングや適当なスレッドで __EditModeScene のタイムスタンプをチェック

・以前のものと異なるようであればプレイモード開始中!

・以前のものと同じであれば、単なるコンパイル


という区別が出来る。



弱点

モロにUnityのversionに左右されるんじゃないだろうか。

あと別に、エディタメニューをコードから実行する形で隠蔽、フラッグをファイルとかに書く、というのも、まあマシで良いと思う。



以上。

wrote 2015/01/19 19:11:14

JenkinsConf2015行って来た


概要

XFDコンテストの話があったはずなんですが1/12(Mon)だと思い込んでて、

はらださんが教えてくれなかったらマジで日程間違えたままだった。


気づきだけをメモしておく。



バージョン管理に組み込むためにJenkinsジョブはshellを実行するだけ

Jenkinsジョブの欄が腐海になるのを防げる手段として常用してたけど、

やっぱ必須テクニックだよね。


ilinxさんの発表より。資料は下記

http://www.slideshare.net/swiftnest/jenkins-43394510


職人芸化を防ぐために使えるほか、


Jenkinsでエラーが出る

-> shell含んでるので各ユーザーの手元でも試せる

-> それで成功する場合、Jenkinsかユーザーのどっちかがおかしい、などの問題の分割がすみやかに行えるのも利点。


自分がJenkinsに用途デザイン面で欲しいのは、「複雑になった動作内容をプロジェクトそれ自体に落とす」というのを推奨する仕掛けなんだけど、

どうすればいいかは思いつかない。別の入り口が必要な気がしている。



1分で終わらなかったらエラーの話

ひきつづきilinxさん。


n分という指定でいいんだけど、ジョブ起動からn分で終わらなかったらエラーにする、っていう手法はなんかこう、斬新でよかった。

ようは、十分に高速なんだけどまだ終わらないとしたらおかしい、みたいなジョブを組んで、

異常検知につかおう、という。


その発想は無かった。良い。


テストの価値は、運を上げること

ひきつづきilinxさん。Q&Aで素晴らしい話がでていたので紹介。


ここらへん聞くのに夢中になっててあれなんだが、意訳すると以下のような問答。


Q.コンシューマゲームの作成に関して、自動テストはどのような価値を生んでますか?

A.デバッガーが運良くその地雷を踏むか踏まないか、という内容に対して、より気づく機会を増やすことができる。


みたいなことをおっしゃってて、このへん超賛成した。


あとデバッグする際に、その問題をreproduceできるかどうかについても、

「一度この動作でエラーが出た」というのはとても信頼できる情報源になる。

バグが直ったかどうかチェックするのにも、このreproduce力がモノを言うし。



botのコード、どこに書く?

ひきつづきilinxさん。講演後に発表者のかたに質問してみた。


Q.テスト用のオートクリアbotのお話されてましたけど、あのbotの動作コードってどこに書いてある感じですか?

A.ゲーム中にハードコード。


非常に身につまされる話で、コードの中の方が、「できることが限定されていてbotを動作させるための入力もやりやすい」という感じ。


ゲーム外からの入力のやりにくさには、主に以下の要因がある。


・キー入力の制限について、いつならどんなタイミングでどのボタンが押せるか、というのを外部からコントロールするのは大変極まる

・画面遷移などのタイミング = 物事が終わったり変わったりした状態の変化をトラックするのが外部からだと面倒、内部からシグナル出すのもまあ面倒

簡単に言うと、AI(画像認識と思考と操作)を作りたい訳ではない、という感じ。



このへんはまだなんかクリエイター間産業とかで成長の伸びしろがあると思う、、んだけど、自分で作りたくはないな。



ワークフロープラグイン

https://jenkins-ci.org/content/workflow-plugin-10

基調講演聞けなかった。ので話をすべてTLで追ってた感じ。


あとで触ってみよう。


TL追ってるかんじだと、

・実行計画を各マシンにgitで保持

・Groovyを使用して描ける

あたりは分かった。



XFDの話

XFD (eXtreme feedback device)

ようは極端にフィードバックする装置で、例えばビルドエラーが出たときにパトランプ回したり、轟音で人を責めたりとかそういうの。

無視しにくくてかつ解決しようという気にさせる必要がある。


ウザすぎると殺人とかに発展するので良くないと思うが、

どこまでなら人間は我慢するのか、みたいなのを実践できて大変面白い。


Unityを使ってXFDのプロトタイピングを行っていたのがなんかこう「ああ、2015年になったんだな」みたいな感じした。


Arduinoの電圧問題みたいなのは新しいverで改善されたとかそんな話をあとで聞いた。



Jenkinsについて最近思うこと

ランナーなのかマネージャなのか、というあたりで分離できるようになるんじゃないかなーと思っている。

Pasted Graphic.tiff

マスタースレーブ構成じゃなくて群体構成で組めないかなー。全体で一個のアスペクトを持つ的な。

未分化な細胞が位置に合わせて分化、特性をもって動作していく、みたいな。


勿論分化はリソースに応じるけど一瞬で、みたいな。


まあ妄想です。



wrote 2015/01/11 16:43:25

UnityでのAssetになった画像ファイルのコピーでインポートを避けることは出来ないという結論


概要

Unityに画像ファイルとかモデルファイルを喰わせる際、

importが走る。


んでこれがまあ、数が数千に及ぶファイルだと辛い。

ここでは、対象をpngとかのフォーマットの画像ファイルに限った話をする。


このimportを発生させずに、素材をUnityに喰わせることはできないか?ということを考えていた。

結論から言うと、一つのプロジェクトではimportを避けるのは無理だった。


でも別のテは使えた。

試した手段を並べる。



手法1 CopyAsset

例えばすでに読みこんだリソースならば、importを再度発生させること無くコピーできるのではないか!?


AssetDatabase.CopyAsset


やってみよう。


var result = AssetDatabase.CopyAsset("Assets/Resources/import/main.jpg", "Assets/Resources/prefabricate/main.jpg");

Debug.Log("result:" + result);


で、これはたしかに読み込まれるんだけど、このあとimportが再度走る。

なぜなんだ、、、、っておもったけど、こいつ、画像ファイルとかに対しては、ファイルをコピーするだけの仕様とのこと。ぐぬぬ、、、


読み込まれたものの概念ごと、ファイル(main.jpg)と設定それ自体をコピーしてほしかったんだけど、

importは走ってしまう。


貴様。


手法2 CreateAsset

名前からして作れそう、、、


var basement = Resources.Load("import/main");


if (basement) Debug.Log("basement is alive!");

else Debug.Log("basement is dead.");


var duplicated = UnityEngine.Object.Instantiate(basement);


AssetDatabase.CreateAsset(duplicated, "Assets/Resources/prefabricate/main.jpg");

Could not create texture from Assets/Resources/prefabricate/main.jpg: File could not be read


殴られるなど。


物の本によると、.mat, .anim, .cubemap, .asset のみしか指定できない。

まあUnityで内部的にも扱えるオブジェクトってなると納得。

納得、、、、なんだが、、、

なんだそのエラーは、、、!!!! 読めなくなったよ的なのがでるんだけど、実際にはオメーこれらの拡張子以外つくれねーじゃねーかww

ありがとう物の本、、って絶版なの、、?

Unity4 ライブラリ辞典 エディタ編



手法2.1 なら.assetで

var basement = Resources.Load("import/main");


if (basement) Debug.Log("basement is alive!");

else Debug.Log("basement is dead.");


AssetDatabase.CreateAsset(basement, "Assets/Resources/prefabricate/main.asset");

Couldn't create asset file because the Texture2D 'main' is already an asset at 'Assets/Resources/import/main.jpg'!


読み出した物からいきなりCreateしようとすると、読んだ大本の奴とおんなじじゃんって殴られる。

管理してるidそれ自体からのコピーではない、と。

ハイ。



手法2.2 ならコピーして

var basement = Resources.Load("import/main");


if (basement) Debug.Log("basement is alive!");

else Debug.Log("basement is dead.");


var duplicated = UnityEngine.Object.Instantiate(basement);


AssetDatabase.CreateAsset(duplicated, "Assets/Resources/prefabricate/main.asset");


var loadFromDuplicated = Resources.Load("prefabricate/main") as Texture2D;

if (loadFromDuplicated) Debug.Log("loadFromDuplicated is alive:" + loadFromDuplicated.name);

else Debug.Log("loadFromDuplicated is dead:" + loadFromDuplicated.name);


うん、いけるな。importも発生しない。まあjpgじゃなくなってるからな。

jpgではなくなってしまった。

jpgではなくなってしまった。

jpgではなくなってしまった。

でも出来たしまあリソースとしてはimportしてたときにセットできてるからなまあいいよな(妥協



ということで、画像ファイルのコピーを行って再importを避ける手段は無い。

packageとかを使えば出来ると思うけどお手軽さからは程遠いな、、まあそれをやってるAssetもあるんだけどさ。




あとはおまけ。





番外 AddObjectToAsset

Assetとして出力する方法で別のかんじで試せるのでは!?

// AddObjectToAssetで子オブジェクトを作ることは出来るっちゃあできるけどやっぱりjpgではなくなる

var basement = Resources.Load("import/main");


if (basement) Debug.Log("basement is alive!");

else Debug.LogError("basement is dead.");


var box = ScriptableObject.CreateInstance("Something");

AssetDatabase.CreateAsset(box, "Assets/Resources/prefabricate/main.asset");


var duplicated = UnityEngine.Object.Instantiate(basement);


AssetDatabase.AddObjectToAsset(duplicated, "Assets/Resources/prefabricate/main.asset");

AssetDatabase.SaveAssets();


var loadFromDuplicated = Resources.Load("prefabricate/main") as Texture2D;

if (loadFromDuplicated) Debug.Log("loadFromDuplicated is alive:" + loadFromDuplicated.name);

else Debug.Log("loadFromDuplicated is dead:" + loadFromDuplicated.name);


出来るが嬉しさは無い。



番外 AddObjectToAsset その2

var basement = Resources.Load("import/main");


if (basement) Debug.Log("basement is alive!");

else Debug.LogError("basement is dead.");


AssetDatabase.AddObjectToAsset(basement, "Assets/Resources/prefabricate/main.asset");

You may not change the path if an object is already peristent in another one

ハイ。



wrote 2015/01/08 10:26:50

2015年予想


概要

タイトルに意味は無い。

こんなこといいなできたらいいなを適当に書いておく。

ウェアラブル(笑)とかはどうでもいいので、そもすでに身につけている物をもっと良くする方向で考えたい。


服に充電機能がついた商品が市場に出回ってほしい

ポータブルバッテリーの極地、着るバッテリーとか実用化されると思う。

電源繊維とかそういうの。


たとえばシャツだったら下のフチらへんからUSB生やすと良いと思う。

sh.png


服充電機能付き家電

洗濯機か乾燥機か収納家具、というかしまってる間に充電的なタンスあたりが出回ると嬉しい。

ハンガーに仕掛けるのも考えたけどシャツとか乾かすときはともかくそれ以外の状態で充電しにくそうなので、充電するのは仕舞うときが良い予感。


充電絹 という単語が流行る

誤変換から拾ってみた。



充電機能のある服だけを扱うメーカーとかできねーかなー。


こちらからは以上です。2015年初の記事だった。





wrote 2015/01/04 21:40:10

Asset bundles cannot include Editor Objects とは一体【解決済み】


概要

UnityでのAssetBundleづくり、コマンドラインからAssetBundle作るところで、

めったに出くわさない気がするエラーに出会った。


原因が知りたいな。



全文

Asset bundles cannot include Editor Objects (Prefab): Assets/AssetRails/temp/Resources/prefabricate/chara/idol_01/prefabricated.prefab.



前提とタイミング

コマンドラインからジョブをくみ上げられるようなものを作っていて、

prefab作成→AssetBundle作成 時に発生した。


作成したprefab自体には問題ないが、そのまま作成したprefabを使用してAssetBundleすると怒られる。

発生するのは、BuildPipeline.BuildAssetBundle メソッド実行時。



回避方法

回避方法はある。

prefab作成、AssetBundle作成ともに、Unityをコマンドラインから使用して動かしているので、コマンドを分けたところ、発生しなくなる。

Unity.exe prefab作成コマンド + AssetBundle作成コマンド -> 失敗

Unity.exe prefab作成コマンド 終了後、Unity.exe AssetBundle作成コマンド -> 成功


このエラーについての情報が集まれば、エレガントに仕留められると思うんだけど。。

助けてだれか、、!



予測

Unity.appの終了時にしか発生しないイベント、みたいなやつがあって、作成したprefabをどうにかしてるのかなーって思っている。


解決編

Unityのお問い合わせにサンプルプロジェクト込みでぶん投げたら、恐ろしい速さで返答をいただいた。

ちなみにサンプルプロジェクトは依存解決に一個失敗してたんだけどな、、、!


Asset bundles cannot include Editor Objects (Prefab): Assets/AssetRails/temp/Resources/prefabricate/chara/idol_01/prefabricated.prefab.

が何を言いたいエラーなのかの説明ももらった。満足だ。



Asset bundles cannot include Editor Objects とは一体

Unity Japanの中の人いわく、


「Asset bundles cannot include Editor Objects ~」は、対象とするオブジェクトがメモリ上のみでアセットとして存在しない時に発生します。

このエラー文ではアセットとして存在しないオブジェクトをエディタオブジェクトと呼んでいます。


とのこと。


つまりpredabがメモリ上のものでしかなく、それをAssetBundleにしようとしたのに駄目だった、ということをさすエラーだったわけだ。



対策

で、実際には処理として、prefabをファイルとして出力したものを読み込んで使用していたのだけれど、

それだけだと駄目で、prefabをファイルとして吐き出したあと、


UnityにAsset自体の情報を覚えてもらうメソッド

AssetDatabase.SaveAssets()

を実行する必要があった。という。

で、実行してみたらめっちゃうまく行った。

回避方法で実現していた内容の真相

これは実に示唆に富んでいる(って書くとカッコいい気がする)


回避方法のところで書いた通り、このエラーは「コマンドラインから再度動かすことで回避できる」ものだった。

つまり、Unity.exeの終了時に、Unityは自動でAssetDataBase.SaveAssets() メソッドを実行しているんだと思う。


それらを明示的に使用すればよい、という感じ。

謎が解けてよかった。


wrote 2014/12/26 11:37:07

フロー図描くためだけのforkとmergeしかない言語「forkerr」


概要

スクリーンショット 2014-12-22 19.32.53.png

無いので作っている。

https://github.com/sassembla/forkerr


ビジュアライザはgraphvizを使用するつもり。

http://www.graphviz.org


実装はここを見てやるつもり。

http://peta.okechan.net/blog/archives/2836



理想

図を吐き出すサービスとしてはこの辺が理想なんだけど

websequencediagrams

https://www.websequencediagrams.com

世のなかにはこういうアプローチのものが少ないっぽい。

ろくなフロー図が描けるツールが無かった。



現状への不満

なんで四角形をいっぱい置いて線で繋がないといけないの? バカなの? 

なんで分岐をN個って書いただけでパァーっと広がる線がでないの? バカなの?

なんで途中で分岐点を追加できないの? バカなの?

どうやってバージョン管理、、あっ画像でやるの? バカなの?


とかそのへん。



不満を殴り殺せば理想がある

ようは、

それっぽい言語でコード書いて、グラフが勝手に出るサイト作ればいいやと思った。

コンパイルエラーで不完全さもナビゲートできるし。

要件は以下

・コードで描ける

・分散(fork)と集結(merge)の2要素だけで描く

・defaultなし、そも母集合を定義したくないのでexhaustも無い

・ブロックで階層を表現

・特定のポイントへのジャンプが可能

・identifierはあるが、階層レベルの無視、有視が選択可能

・コードだからバージョン管理できる


以上が図ツールとしては必須な条件だと思っている。

これをサイト上で走らせればいい感じ。



今のところの式

fork TopLevel {

entry: {

fork SecondLevel {

a: {


}

b: {


}

c,d: {


}

withComment:COMMENT {


}

willMerge: {

merge TopLevel

}

_:{


}

}

}

_: {

merge exit

}

}

最終的にはこういうのがコードで描けると良いと思っている。

FlowDiagramVert.png

wrote 2014/12/22 19:08:39

Unityの地味に勤勉な挙動


概要

特に必要の無い地味な知識を提供。



importからのimportは発生しない

Unityに画像とかを放り込んで発生する読み込み処理について、

まあ適当にimportとか呼称してるんだけど、


たとえばPostProcessor系の処理で、読み込み処理中にファイルを作ったりした場合、

その瞬間では読み込みが発生しない。 つまり.metaファイルが作られない状態が形成できる。


ネストとか無限ループするのを避けてるっぽい。

安全。



importの動作

Project Settings で visible meta files を選んでいる場合は、

次のような動作が確認できる。

・.metaファイルが存在していない場合、読み込みが発生する

・読み込み後、.metaファイルが作成される

・内部DBにも登録される(たぶん.metaファイル内でのGUIDとフォルダパスをキーにしてる)



importのタイミング

importの発動するタイミングは以下の通り

・Unity起動中

・Unity起動時



放り込み方による差

.metaファイルが無いものに対して、DBへの登録と読み込み、.meta作成が行われる。

.metaファイルがあったとしても、DBへの登録が存在しない場合がありえる。

たとえばimport後のフォルダをAssetsフォルダ外部に持ち出してUnityを終了し、

Unity起動時にAssets以下の別フォルダに放り込んだ場合。


その場合は、.metaファイルの情報をもとに、importをスキップして読み込んでDB登録してくれるケースと、

GUIDだけが書き変わってimportをスキップして読み込んでDB登録してくれるケースと、

importのスキップが発生せず読み直しが発生するケースがある。


GUIDだけが書き変わるケースだと

The GUID for Assets/AssetRails/temp/Resources/prefabricate/chara/idol_01 is already in use by Assets/AssetRails/temp/Resources/import/chara/idol_01. Assigning a new guid.


って言われる。

wrote 2014/12/21 16:06:36

Mac OS X YosemiteJenkinsを動かすために必要なこと


概要

一応書く。

ケースとしては、

Mac用のPackageを公式から落としてきてそのままの権限でとりあえずうごいてくれればいい、

そしたらママもう何も言わない、 みたいなケース。

まあこのあとgitとかの権限で必ず揉めるんだけどさ。



Javaが必要(わすれがち)

インストールしましょう。

次の手順に気を取られて忘れてて、初めてJavaがない場合どんなエラーだすか見た。

公式PackageでYosemiteにJenkinsをインストールすると、

Macにデフォで入ってる自動launch支援ツール launchdに対して設定が組み込まれる。

で、ここでは、exe(か、shell?)経由でPackageでインストールされたJenkins.warあたりをぶっ叩いているのだけれど、

Javaがインストールされていない場合、

pair of (jenkinsci, Jenkins.war) does not exist


みたいなエラーが出る。

このエラーが出た場合、ってわけじゃないんだけど、.warって文字列をみて、

「あっJavaいれてねーや」

って思い出した。



Yosemite、ログ吐くところの権限設定が必要

いままでと違うところで、知るはずも無い。


Jenkinsさん、Packageでインストールすると、jenkinsという名前のユーザーを勝手につくる。

で、このユーザーに対して、/var/log/jenkinsフォルダへの書き込み権限が無いので、

無限に起動に失敗する。

(インストール時にやってくれればいいんだけどな。)


com.apple.xpc.launchd がエラーをログとして残しているので、

Console.app とかで見よう。


権限調整すれば完了する。

sudo chown jenkins /var/log/jenkins


もしJenkins自体の実行権限をjenkins ではなく rootとかに変える場合、

パッケージでインストールしていると、Jenkinsの起動にはlaunchctlが勝手に組まれているので、

launchctlに仕込まれているジョブ? をunloadしたりする必要がある。

http://sassembla.github.io/Public/2013:05:13%2016-23-21/2013:05:13%2016-23-21.html



それでも死ぬ場合

すでに吐いたログファイルを消すと生き返ったりする。

吐き出すjenkins.logの権限が変わったりすると、上書きできずに死ぬっぽい。

なんで変わるのかは追えてない。

wrote 2014/12/17 17:51:38

AssetBundleを高速に作る


概要

Unity Advent Calendar 2014 15日目の記事です。

http://qiita.com/advent-calendar/2014/unity


Unityを使う上でめっちゃ困る事象である

「platformをswitchしたときクッソ重い」

を簡単に避ける方法を見つけたので、書く。


ほんとはAssetStoreに新Assetを入れた(申請中)のを記事にしたかったんだけど、

むしろこっちの方が良い話だろうという感じ。



解決したかったこと1

Unityを使って複数プラットフォームでの開発をしていて困ること、のなかで、

「プラットフォーム切り替え時」

の時間がかかることがかなり上位に来ると思う。



既知の有償な手段:fast platform switch を使う

http://jemast.com/unity/fast-platform-switch


有償、かつ有効。



オルタナティブな手段:拡張子を変える

で、もっと簡単に、手軽にできるんじゃねーの?っていうアイデアがこちら。


「ファイルの拡張子をUnityがどうしようもないものに変える」というもの。

実際に試してみたところ、マジで実現できた。

のだけど!!!


エラーが出る条件があって、

それを避けようとやってみればみるほど、fast platform switchの手法にメッチャ似てきて、


これを公開すると

ただ単に「fast platform switch」に喧嘩を売るだけになってしまう


ということがわかった。

つまり新規性が無い。

なんとかして新規性を獲得しようと思ったんだけど無理だった。


ので、別の問題を解決することにした。

現在 2014/12/14 23:05:36











解決したかったこと2

AssetBundleを高速に作る


箇条書きにすると、


1. あるプラットフォーム向けのAssetBundleを作るとき、エディタの環境設定がそのプラットフォームになってしまい、

AssetBundleにしたいファイル以外のファイルも、プラットフォームの変更に巻き込まれて再度importされてしまう。

これはメッチャ遅いし時間掛かってストレスフルなので、再度importされないようにしたい。

2. ファイルを移動するようなコードを書きたくない。

3. 複数のプラットフォームのAssetBundleを連続で高速に作成したい。


1が特にわっかりにくいと思うので具体的に説明する。



説明

以下のような構成で、AssetBundleにしたいファイルがProject内、Resourcesフォルダ下にあったとしよう。

スクリーンショット 2014-12-15 1.44.18.png

AssetBundleにしたい素材が入っているフォルダ BundlizeTargetの中身はこう。

スクリーンショット 2014-12-15 1.47.10.png

対して、AssetBundleにしたくない素材が入っているフォルダNeverReImportの中身がこう。

スクリーンショット 2014-12-15 1.48.44.png

ここで、BundlizeTargetフォルダの中身だけを、iOSとかAndroid用に、AssetBundleとして吐き出したいとする。

ad.png

AssetBundleを作るときの手順のおさらい

1. リソースを用意する

2. スクリプトで以下のようなのを書く

var res1 = Resources.Load(Path.Combine(targetFolderName, "Yeaaahhhhh"));

var targetPlatform = BuildTarget.iPhone;// Unity5だとiOSになったな~

uint crc;

if (res1 != null) {

BuildPipeline.BuildAssetBundle(

res1,

null,

Path.Combine(destinationPath, "Yeaaahhhhh_bundlized"),

out crc,

BuildAssetBundleOptions.CollectDependencies | BuildAssetBundleOptions.CompleteAssets,

targetPlatform

);

}

}


3. 実行する

4. 実行後には、エディタのプラットフォーム設定は、BuildPipeline.BuildAssetBundleメソッドの内容で使われたプラットフォームになっている。

つまりどこかでプラットフォームスイッチが発生している。



実際にプラットフォームが変更されるのは、3. の内部で、まさにBuildPipeline.BuildAssetBundleメソッドが実行された瞬間になっている。

ちなみに例えばAssetBundleの吐き出し先が無いとかでエラーになっても、プラットフォームはスイッチされる。



プラットフォームスイッチが発生すると

AssetBundleにしたいBundlizedフォルダ以外にも、Assetsより下の素材的なファイルはだいたい根こそぎ、再importされる。

(ソースコードとか.unityファイルとかは再度importされない。)

で、

1__#$!@%!#__スクリーンショット 2014-12-15 1.44.18.png

AssetBundleに変えたくないファイルも、再度importに巻き込まれる。

そして何より問題なことが一つ。


importは、遅い。

特にiOS、Android用のimportは、画像、サウンド、3Dモデルなどすべてにおいてクッソ遅いし重い。


余計なファイルをimportすることは辛い。

ということは、余計なファイルをimportしないようにすれば、高速化できるのでは?


っつーことでやってみた。



解決策

AssetBundleを作る瞬間に、

AssetBundleにしたくないファイル全部の拡張子を、

Unityが気にしない物に変更する。


プロジェクトはこちら。

https://github.com/sassembla/PlatformSwitcher

名前は気にしないでください。



プロジェクトを適当にDLしてきて、

メニュー > Window > Bundlize で、Bundlizeフォルダの中身を高速にAssetBundle化する。

iOS用、Android用の順に、計2つのAssetBundleを、PlatformSwitcher/Bundlized フォルダ内に吐き出す。

スクリーンショット 2014-12-15 2.27.57.png


その際、AssetBundle化が完了するまでの間、NeverReImportフォルダの中身は再度importされない。

つまり無駄なimportが無く高速。



手法解説

1. プラットフォームスイッチでimportされる可能性のあるファイルの拡張子をすべて + .deactivate 付きに変える(deactivate化)

2. 開始前のプラットフォームを記録しておく

3. AssetBundle化したいやつだけdeactivateを解く(activate化)

4. AssetBundleを好きなだけ作る

5. 3で保存しておいたプラットフォームに戻す(今回はダミーAssetBundleを作ることで無理矢理戻している)

6. 1で変えたファイルの拡張子を全部戻す

ね、簡単でしょう?



状況解説

実行部分だけだとこんな感じ。

using UnityEngine;

using UnityEditor;


using System;

using System.IO;

using System.Collections.Generic;


class AssetBundleContainer {

[MenuItem ("Window/Bundlize", false, 1)]

static void AssetBundlize () {

// Bundle化したあとのモノの置き場を適当に作る

var destinationPath = "Bundlized";

FileController.Renew(destinationPath);


/*

deactivate

対象が含まれる、すべての「importされると面倒なファイル」を、importされなそうな拡張子にリネームする。

*/

var deactivateTargetPath = Path.Combine(Application.dataPath, "Resources");

var transactionId = Deactivator.DeactivateFilesUnderPath(deactivateTargetPath);

var targetFolderName = "BundlizeTarget";

var targetFolderPath = Path.Combine(deactivateTargetPath, targetFolderName);


// 現在のプラットフォームを記録

var beforePlatform = EditorUserBuildSettings.activeBuildTarget;


// AssetBundleにする対象のファイルの拡張子だけを戻す(この場合フォルダ単位で戻している)

Deactivator.ActivateFilesUnderPath(transactionId, targetFolderPath);


// iOS用にAssetBundleを作成

if (true) {

var res = Resources.Load(Path.Combine(targetFolderName, "Yeaaahhhhh"));

var targetPlatform = BuildTarget.iPhone;// Unity5だとiOSになったな~

uint crc;

if (res != null) {

BuildPipeline.BuildAssetBundle(

res,

null,

Path.Combine(destinationPath, "Yeaaahhhhh_bundlized_ios"),

out crc,

BuildAssetBundleOptions.CollectDependencies | BuildAssetBundleOptions.CompleteAssets,

targetPlatform

);

}

}


var afterPlatform1 = EditorUserBuildSettings.activeBuildTarget;

Debug.Log("after1:" + afterPlatform1);



// Android用にAssetBundleを作成

if (true) {

var res = Resources.Load(Path.Combine(targetFolderName, "Yeaaahhhhh"));

var targetPlatform = BuildTarget.Android;// Unity5だとiOSになったな~

uint crc;

if (res != null) {

BuildPipeline.BuildAssetBundle(

res,

null,

Path.Combine(destinationPath, "Yeaaahhhhh_bundlized_android"),

out crc,

BuildAssetBundleOptions.CollectDependencies | BuildAssetBundleOptions.CompleteAssets,

targetPlatform

);

}

}


var afterPlatform2 = EditorUserBuildSettings.activeBuildTarget;

Debug.Log("after2:" + afterPlatform2);


// リセット

if (true) {

uint crc;

var resetterRes = Resources.Load("dummyText");

if (resetterRes != null) {


BuildPipeline.BuildAssetBundle(

resetterRes,

null,

Path.Combine(destinationPath, "resetter"),

out crc,

BuildAssetBundleOptions.CollectDependencies | BuildAssetBundleOptions.CompleteAssets,

beforePlatform

);

}

}


var afterPlatform3 = EditorUserBuildSettings.activeBuildTarget;

Debug.Log("after3:" + afterPlatform3);


// 無効化していたのを元に戻す

Deactivator.RollbackTransaction(transactionId);

}

}


class Importer : UnityEditor.AssetPostprocessor {

public void OnPreprocessTexture () {

Debug.LogError("assetPath:" + assetPath);

}

}



プラットフォームスイッチが発生すると、再importが発生する。

再importが発生すると、OnPreprocessTextureメソッドが呼ばれ、

Debug.LogErrorが走ってあぶなーーーいっ! って言ってくれるようになっている。



で、先ほどのフォルダ構成に対して、

2__#$!@%!#__スクリーンショット 2014-12-15 1.44.18.png


1. プラットフォームスイッチでimportされる可能性のあるファイルの拡張子をすべて + .deactivate 付きに変える(deactivate化)

/*

deactivate

対象が含まれる、すべての「importされると面倒なファイル」を、importされなそうな拡張子にリネームする。

*/

var deactivateTargetPath = Path.Combine(Application.dataPath, "Resources");

var transactionId = Deactivator.DeactivateFilesUnderPath(deactivateTargetPath);



2. 開始前のプラットフォームを記録しておく

// 現在のプラットフォームを記録

var beforePlatform = EditorUserBuildSettings.activeBuildTarget;



3. AssetBundle化したいやつだけdeactivateを解く(activate化)

// AssetBundleにする対象のファイルの拡張子だけを戻す(この場合フォルダ単位で戻している)

Deactivator.ActivateFilesUnderPath(transactionId, targetFolderPath);


4. AssetBundleを好きなだけ作る

// iOS用にAssetBundleを作成

if (true) {

var res = Resources.Load(Path.Combine(targetFolderName, "Yeaaahhhhh"));

var targetPlatform = BuildTarget.iPhone;// Unity5だとiOSになったな~

uint crc;

if (res != null) {

BuildPipeline.BuildAssetBundle(

res,

null,

Path.Combine(destinationPath, "Yeaaahhhhh_bundlized_ios"),

out crc,

BuildAssetBundleOptions.CollectDependencies | BuildAssetBundleOptions.CompleteAssets,

targetPlatform

);

}

}


var afterPlatform1 = EditorUserBuildSettings.activeBuildTarget;

Debug.Log("after1:" + afterPlatform1);



// Android用にAssetBundleを作成

if (true) {

var res = Resources.Load(Path.Combine(targetFolderName, "Yeaaahhhhh"));

var targetPlatform = BuildTarget.Android;

uint crc;

if (res != null) {

BuildPipeline.BuildAssetBundle(

res,

null,

Path.Combine(destinationPath, "Yeaaahhhhh_bundlized_android"),

out crc,

BuildAssetBundleOptions.CollectDependencies | BuildAssetBundleOptions.CompleteAssets,

targetPlatform

);

}

}


var afterPlatform2 = EditorUserBuildSettings.activeBuildTarget;

Debug.Log("after2:" + afterPlatform2);


ここで、Debug.Logの内容は計2つ出る。(Pro版持ってないとそれはそれでエラー出て怒られる)


5. 3で保存しておいたプラットフォームに戻す(今回はダミーAssetBundleを作ることで無理矢理戻している)

// リセット

if (true) {

uint crc;

var resetterRes = Resources.Load("dummyText");

if (resetterRes != null) {


BuildPipeline.BuildAssetBundle(

resetterRes,

null,

Path.Combine(destinationPath, "resetter"),

out crc,

BuildAssetBundleOptions.CollectDependencies | BuildAssetBundleOptions.CompleteAssets,

beforePlatform

);

}

}


var afterPlatform3 = EditorUserBuildSettings.activeBuildTarget;

Debug.Log("after3:" + afterPlatform3);

実際、プラットフォームの変更は,

EditorUserBuildSettings.SwitchActiveBuildTarget メソッドでも変更可能なんだけど、


ここでなんでAssetBundle作る方法を使っているかというと、

バッチから実行したいから。

EditorUserBuildSettings.SwitchActiveBuildTarget メソッドはバッチ上では使えない。



6. 1で変えたファイルの拡張子を全部戻す

// 無効化していたのを元に戻す

Deactivator.RollbackTransaction(transactionId);



この順で動作すると、importされる内容は、開始時のプラットフォームがPCプラットフォームだった場合、

・iOSプラットフォームに一度変更、BundlizeTarget フォルダ内の画像 Yeaaahhhhh.jpeg だけが変換される

・その後Androidプラットフォームに変更、BundlizeTarget フォルダ内の画像 Yeaaahhhhh.jpeg だけが変換される

・最後にPCプラットフォームに戻り、BundlizeTarget フォルダ内の画像 Yeaaahhhhh.jpeg だけが変換される

・無効化されていた画像が復帰

という感じになる。


完璧、、、!! かに思えたのだが、


実は最後にぶり返しみたいなのがあって、

無効化されていた別フォルダのものが復帰後、再度Unity Editor.appにフォーカスをあてるとかすると、PCプラットフォームとして変換される。

(PCプラットフォームだと高速っちゃあ高速なので気にはならないが。)


プラットフォームスイッチに巻き込まれる分の時間は確実に減っている。


で、実際どのくらい速いの?

コマンドラインから実行して時間を計測してみた。


deactivateあり:

ts:00:00:01.9974540 (1.9秒



deactivate無し:

ts:00:00:03.9435570 (3.9秒



だいたい2倍なんだけど、、地味だな、、、ファイル数あたり2秒かかってるだけ。



試しに邪魔なファイルを増やして実行

呪われたみたいな絵面のNeverReImportフォルダ

スクリーンショット 2014-12-15 2.58.47.png

deactivateあり:

ts:00:00:02.8803690 (2.8秒



deactivate無し:

ts:00:00:50.5550690 (50.5秒



速い。(確信)

deactivateありの0.8秒くらいの増加は何だろう。あとで調べよう。



気づき

、、、、


書いてて気づいたんだけど、別にAssetBundleにするやつも、Resource.Loadとかで読み込んだあとだったら、

deactivateして良かったのでは。


そしたらその分のimportも無くて、もっと速かったな???



おまけ小ネタ

Editor用のScriptを書いていて、「現在の設定」を表示したいときがある。

スクリーンショット 2014-12-14 22.39.34.png

接続状態を表したかったり、

モードを表したかったり。


で、このような見た目になるインターフェースをつくってしまったことがあった。

connect と disconnectが排他でconnect状態だからdisconnectが押せる、とか

現状autoConnectがonだからoffが押せる、とか。


メニューからのプルダウンで、状態を表示したいだけなんだけど、こう、なんだ、2つ持たなきゃ行けないという。

コードの量も多い。


これが、例えばだけど、こう書くことで単純に解消できた。


#if UNITY_IPHONE

[MenuItem ("Window/changePlatform/Now: iOS Platform", false, 1)]


#elif UNITY_ANDROID

[MenuItem ("Window/changePlatform/Now: Android Platform", false, 1)]


#elif UNITY_STANDALONE_OSX

[MenuItem ("Window/changePlatform/Now: OSX Platform", false, 1)]


#endif

public static void CurrentPlatform () {}// こいつは実際どうでもいい、ただメニューでぶったたかれる関数が必要。気に喰わなければdisableにすればより良い。


compiler directiveで、メニューに出てくる項目を弄ると、

directiveに何かをセットするようなコードを状態セットのあとにいれるだけで、

メニューに表示される文言 = 状態表示を弄れる。


たとえば上記のコードだと、現在のプラットフォームがPCなら、プルダウンメニューに表示される項目はこんな感じになる。

スクリーンショット 2014-12-14 22.44.53.png

メニューで状態が表示できた。

この例だとUnity Editor自体の上部バーをみればまあ分かるじゃんって感じなんだけど、

まあ例として。

ちなみにこの方法には欠点があって、

状態が変わる→コンパイルが発生する、という段取りをこなさないと、compiler directiveが変化せずに表示が変わらない。


書き終わった。

2014/12/15 3:54:34

wrote 2014/12/15 00:00:00

LapsodyRepartureとかそういう名前で言語作りたい


概要

サービスを複数のpeerで構成、連携させて動かすとき、


フローを制御するのに専念する言語と、

フローから逸脱して処理を行い、フローに合流するか消滅するだけの用途の言語を、

共有領域持ったままシームレスにぶっ叩けるように

意図的に分けて作ると面白いのではないかみたいな話してた。



由来

Lapsodyは「経過」を表すLapseのもじり、

Repartureは「出発」って意味のDepartureのもじり。


目的

1.サービスの全体フローを一つの言語で見渡しよく描く

2.合流、離脱を行う処理をフローとは分けて書く

3.分散環境で面倒くさい「merge」や「abort」を可視化しやすくする

4.サービスの部分死を可能にする



仕様というか気分

・分散VMとかで動作して

・peerを超えるの前提で

・Lapsody側でループだったりストリームだったりを扱って

・Reparture側で枝化と処理完遂からの合流を行う

・ごく薄い、混ぜて書ける領域と、別離された領域を持つ

・それぞれの言語のkeywordにはlmatchとかrmatchみたいにl,rをそれぞれ頭につける

・2つmodeがある格ゲーキャラみたいな立ち位置を目指す

temp9507.png


動作イメージ

Lapsodyで機関全体の制御を集中しておこなう。状態は持たず、フローの束をもち、必ず永続する。

Repartureで「一度離反して合流」か「離反してそれっきり」みたいな動作を行う。


Lapsody側とReparture側の中継ポイントにはportみたいなものが配置されて、離脱記録とか合流記録を保持し、

スケーリングもこのポイントを主点にして行う。

zu.png


これで、意図的に打ちっぱなしや合流が書ける。


複数のフローを持つようにつくる(一つのサービスに対してLapsodyが複数のインスタンスを持つ)のを禁止したほうがよさそうな

気がする。

wrote 2014/12/14 0:01:43

通信障害とGoogle Play Store App


概要

Androidで通信状況がアレなときに、

Platformの用意したサーバと連絡がとれないくせに購入できたことにするGoogleさんのPlayStoreAppの仕様最高にロックだぞみたいな事案にあたった。

きっと悪い夢だ。俺の使ってるプラグインとかコードのバグに違いない。



内容

以下のような手順で発生する。

Pasted Graphic.tiff

・StoreAppの通信失敗が原因での失敗なのにUser Cancelled扱いにする

・そのくせ課金は済んでるのでどっかのタイミングでinventoryに購入済み状態でレシートが現れる


みたいなの闇で楽しい。


UnityでAndroidのやつ作ってて見つけた挙動なので、Prime31とかのプラグインがUser Cancelled を返してるのかも知れないので、

追う。




メモ for https://www.websequencediagrams.com

client ->+ playStoreApp: start purchase


playStoreApp ->+ google: start purchase


note right of google


ここで、ユーザーが購入可否を提案され、

購入しますか? ハイ を押した瞬間に端末をオフラインにすると、


clientがplayStoreAppから受け取る返答は

User Cancelled (-1005) になり、


さらにplayStoreAppには「購入済み」状態でチケットが発生、

その後のclient内でのqueryInventoryとかでの取得で

「購入済み」状態で確認できる。


つまりこれ、課金はされてるのでは?

オフラインになって通信失敗したのにUser Cancelledにしたり

課金されたりでうん???っていう気持ち。


clientとplayStoreAppの間をプラグインで実現してるんで、

その間でUser Cancelledはコードのミスとかで

発生しているかもしれないが、

チケットが発生するのはどうなのこれ。

end note


google-->-playStoreApp: ???


note right of playStoreApp


課金チケット爆誕、

以降適当なタイミングで

inventoryに現れるようになり、

その状態は0 = purchased

end note


playStoreApp-->-client: User Cancelled


note left of client

えっ

キャンセルなんかしてねーし

end note


wrote 2014/12/12 12:10:17

無秩序なif-elseは死ねば良いのに


概要

ポエムです。



無秩序なif-elseは死ねば良いのにと思う理由

if-else書かなきゃいけないとき、それが

if {} に対して排他的な要素をelse {} に書かなきゃいけないんだが、


if situation {

route A

} else {

route B

}


なんっつーーーか単純に負けた感じするんだよな。

状況を読み切れてないというか、打算的ではない感じがする。

考えるのサボったんじゃねえのみたいな。



変更可能性を高く保ちたい

自分が感じるif-elseの最高に嫌いなところは、

if-elseなコードは将来の変更可能性を著しく損なう ということにある気がした。


あとで変更加えるときに


「これはelseにくる場合の可能性をどれだけ考慮してるか」


っていうのを「変更したくなったその都度、コードから」見ないといけない。

これはとてもとても面倒臭い。


で、読むのが面倒くさい = 取りうる値が自明であることが読みにくいコード = 変更可能性が低いコード、

という式が自分の中で成立してしまう。


状態を持ったコードなんかもそうなんだけど、

状態を持たないコードであっても、値の範囲がパッと読めないだけで苦しくなる。


で、これをどう改善しようかみたいに考える。



例を殴って直そう

例えば

string a = GetResult


if a == “something” {

route A

} else {

route B

}


みたいなコードがあったとして、elseに来る可能性があるaの中身は、実際なんだろう。

スッゲー膨大になるよな。


route Bにくるときのパターンは “somethingではない” くらいの情報しか無い。

これを今から殴りたい。


自明化

できればif文に乗ってくる要素がcontextとして一列に並べられるような設計にして、

かつそれらを選択肢が網羅していることが自明であると嬉しい。


まずは取り得る選択肢の幅そのものを小さくできないものか。


enum a = GetResult


if a == enum .enumA {

route A

} else {

route B

ここにくるのは少なくともenumに定義された何かっぽい気がする

}


このへんがif-elseの限界で、行き詰まる。

で、じゃあif捨てよーぜって感じで、switchとかmatchとか。

この時点で選べない言語が出てくるが気にしない。


enum a = GetResult


switch a {

case enum.enumA:

route A

break


default:

route B

break

}


さらに、取り得る選択肢がexhaustiveな要素だと自動的に明示できるようだと素晴らしい。

けどこれは出来る言語見たこと無い。


enum a = GetResult


switch a {

case enum.enumA:

route A

break


default: <- not exhausted yet. enum.enumB, enum.enumC is not used in this block

route B

break

}


default(wildcard)があるにも関わらず、ピンクな部分のエラーを出せる言語を自分は知らない。

っていうかshould exhaustなenumとかがあればそういうのできる言語ありそうな気がする。

ここから先はスピリチュアルな変更を伴う感じの調整が出来る。

そもそもenumの要素がすべて現れ、かつ使われるような要素になるように

「考え直す」とか。


飽きたのでここまでにする。


ぶっちゃけコンパイラが賢い言語でswitchとかmatchが使えると平滑にする術が増えるし

幸せになれるなって感じ。

転じてifの価値は低い。




オチは無いです。

wrote 2014/12/11 23:58:10

SublimeTextのAPIを外部から纏めて叩くやつ


概要

Sublime Text Advent Calendar 2014

http://www.adventar.org/calendars/407


12/5 に飛び込みで来ました、@toru_inoue です。

前日は霙(@xxmiz0rexx)さんでした。

http://webimemo.com/other/7926

自分が紹介するのはこんなのです。



SublimeSocket

https://github.com/sassembla/SublimeSocket3


Sublime Text のAPIを、ネットワークとかWebSocket越しにぶっ叩いたりできます。

ネットワーク越しに複数のSublime Text 間でチャットしたり、

コードにハイライトやエラー表示をしたりするのに使っています。



例えば

通常のAPIを使ってやるんだとわりと面倒な、

1.特定の行の文字を囲んで

2.赤丸のあたりを押したらツールチップを出す

スクリーンショット 2014-12-05 1.00.06.png


みたいなことが、JSONっぽい式を渡すと外部から動かせるようになっている。

で、今回はアドベントカレンダーってことで、ちょっとしたサプライズとして、皆さんのSublime Textに何かを送り込んでみようと思う。


デモ

実際に動かして(動かされて)みよう!

☆Mac用しか用意できませんでしたすいません。



1.SublimeSocketパッケージをインストール

下記からDLして解凍、Sublime Text のPackageパスに置くと良いと思う。

Sublime Text 2の場合 -> Download ZIP

Sublime Text 3の場合 -> Download ZIP



2.次のファイルもダウンロード

テキストファイルです。あとで使います。

https://dl.dropboxusercontent.com/u/36583594/outsource/something.sushijson


中身はこんなの。

showAtLog: {

"message": "hello world!!"

}

->showDialog: {

"message": "自動的にファイルが一個作られます。 1分もしないうちに消えると思いますが、お楽しみください。 @toru_inoue"

}

->createBuffer: {

"name": "hello_its_new_text"

}

->modifyView: {

"name": "hello_its_new_text",

"add": "はいこんにちわ。 ",

"injects": {

"add": "message"

},

"selectors": [

{

"showAtLog<-message": {}

}

]

}

->wait:{

"ms": 1000

}

->modifyView: {

"name": "hello_its_new_text",

"add": "今実行したファイルで、 ",

"injects": {

"add": "message"

},

"selectors": [

{

"showAtLog<-message": {}

}

]

}

->wait:{

"ms": 1000

}

->modifyView: {

"name": "hello_its_new_text",

"add": "この文章が自動的に書かれています。 ",

"injects": {

"add": "message"

},

"selectors": [

{

"showAtLog<-message": {}

}

]

}

->wait:{

"ms": 1000

}

->modifyView: {

"name": "hello_its_new_text",

"add": "あと3行くらい書いて止まると思います。 ",

"injects": {

"add": "message"

},

"selectors": [

{

"showAtLog<-message": {}

}

]

}


->wait:{

"ms": 1000

}

->modifyView: {

"name": "hello_its_new_text",

"add": " ",

"injects": {

"add": "message"

},

"selectors": [

{

"showAtLog<-message": {}

}

]

}


->wait:{

"ms": 1000

}

->modifyView: {

"name": "hello_its_new_text",

"add": "こんな感じで書き足すことが出来たり、",

"injects": {

"add": "message"

},

"selectors": [

{

"showAtLog<-message": {}

}

]

}


->wait:{

"ms": 100

}

->modifyView: {

"name": "hello_its_new_text",

"add": "思ったより素早く書いたりできます。",

"injects": {

"add": "message"

},

"selectors": [

{

"showAtLog<-message": {}

}

]

}


->wait:{

"ms": 10

}

->modifyView: {

"name": "hello_its_new_text",

"add": "フフフ、怖いか? ",

"injects": {

"add": "message"

},

"selectors": [

{

"showAtLog<-message": {}

}

]

}


->wait:{

"ms": 1000

}

->modifyView: {

"name": "hello_its_new_text",

"add": "赤線で囲んだり、 ",

"injects": {

"add": "message"

},

"selectors": [

{

  "appendRegion": {

"line": "7",

"message": "",

"name": "hello_its_new_text",

"condition": "keyword"

}

}

]

}

->wait:{

"ms": 1000

}

->modifyView: {

"name": "hello_its_new_text",

"add": "選択肢を出すことが出来たりします。すごくね??",

"injects": {

"add": "message"

},

"selectors": [

{

  "showToolTip": {

  "name": "hello_its_new_text",

"onselected": [

{

"はい": [

{

"showDialog": {

"message": "ワーイ!! というかんじのやつです!",

"selectors": [

{

"closeFile": {

"name": "hello_its_new_text"

}

}

]

}

}

]

},

{

"いいえ": [

{

"showDialog": {

"message": "ァ、、ァ、、以上です。",

"selectors": [

{

"closeFile": {

"name": "hello_its_new_text"

}

}

]

}

}

]

},

{

"どちらとも言えない": [

{

"showDialog": {

"message": "そんな曖昧な君が好き。嘘です。以上です。",

"selectors": [

{

"closeFile": {

"name": "hello_its_new_text"

}

}

]

}

}

]

}

],

"oncancelled": []

}

}

]

}



3.Sublime Textを起動してコマンドパレットからsublime socket: run SushiJSON

super + shift + p -> sublime socket: run SushiJSON

スクリーンショット 2014-12-05 1.09.44.png


4.下のほうに入力窓が出てくるので、2でDLしたファイルを指定してエンター

こんな感じ。 入力が終わったらエンターを押してください。

bottom.png


すると、

寸劇が始まります。

スクリーンショット 2014-12-05 3.00.22.png

いかがだったでしょ。




明日はcipherさんです。

wrote 2014/12/05 00:00:00

Goconって来た


概要

これでした。

http://gocon.connpass.com/event/9748/


当日9時くらいに繰り上がったよって来てたので、昼飯後のピックアップで入れてもらえた。

横浜からだとどんなに頑張っても1時間以上掛かってしまうので基調講演とかが聞けなくて無念。


めっちゃ面白かった。

以下簡単にメモ



mackerel-agentの話

発表資料

http://songmu.github.io/slides/gocon2014-autumn/#0


goで書かれてる、mackerelのhostに対して情報送る系のツール


os.Interrupt を使ってWinとかにも対応

定期更新する部分


https://github.com/mackerelio/mackerel-agent

読んで定期実行まわりとかパクってみたい。


profilerの話

runtime/pprof の話


モンテカルロ法っぽいかんじで、どこが重いかを見る


発表資料

http://www.slideshare.net/InadaNaoki/gocon2014-pprof

HTTPとかから使うなら

net/http/pprof 

HTTP API for pprof


1.4からはpure goな実装になってる

cachegrind

っていうツールがあるそうな

アセンブリに対しての解析すげええ。 1.4から。


スタックトレースとか見たいと思うので、葉に対してしかインライン展開での最適化はされない

(デフォルトだと、みたいな感じで、コマンドラインで弄れば変えられるらしい。


それ以外にも葉に対する最適化ある。



NSQの話

完全に知らなかった。


Distributed statics processing

分散統計処理用のライブラリ

QOSみたいな設定がある。


https://github.com/bitly/nsq

bit.lyが使ってるのか。



Unit-testing programs depend on I/O in Go

資料

https://yuya-takeyama.github.io/presentations/2014/11/30/gocon_2014_autumn/


なるほどReader/Writerのレベルから偽装してるのか。


ケツについて

某社さんの椅子よりはケツクラッシャビリティ高くなかったのですごく快適でした。

gocon実行委員の皆様、とてもいい機会と環境をどうもありがとうございました。


wrote 2014/11/30 14:26:39

PluggyLockで「スマフォ落としても平気」という方向で問題解決した話


概要

なんで物体は落ちるんだろうな。iPhone6一度落とした時にその威力を痛感した。

あとこないだデジゲー博で目の前で知らない人のNexus5の液晶がイッたの見ちゃってトラウマで心が痛んだ。


iPhone6、そのまま持ってるとツルツルすぎて落とすな?

でもカバーとかダサくてポッケのなか入れにくくなってムカつく。

さらに落としたらどうなっちゃうの、っていう問題を根本的に解決できてない。


のでカバー付けるという策はなんとかして避けたい。



で、PluggyLockの存在をさきらさんのTweetで知ったので購入、使用してみた。

PluggyLock

http://www.pluggylock.com


ミニプラグのジャックに入れて固定、ストラップ用のリングにできる金具。


iPhone6とかNexus5に付けてみたとこ

iPhone6

B2ciuXKCEAAC8VA.jpg



Nexus5

B2ciuXKCUAAPgfC.jpg



値段

本家だと最高$26.00で扱っている。

自分のときは輸送費含めてこんな感じの金額になった。

スクリーンショット 2014-11-22 21.06.21.png

購入にはPaypalとかも使える。



購入ルート

本家のサイトから注文して

http://www.pluggylock.com


2wくらいで届く。


購入完了時の「受け付けました!」メール以外、一切連絡が無く届く。

感想

最高。

wiiリモコン持ちしてる。

10012978621.jpg

さすがにウデに付けっぱなしはあり得ないくらいダサいので、

着脱に余裕がありつつ、手から落としたときに千切れなそうなやつを選んだ。


下みたいなカテゴリのやつ。

o06000600120215candpa.jpg

iPhone6 + PluggyLock + ストラップ。


便利だ。

wrote 2014/11/22 20:58:31

プロジェクト・人が起き上がってこない絨毯を作ろう


概要

寒くなってくるしぬる舗渋谷で夜あそんでから家で寝る、みたいなパターンが増えてくると思うので、

あそべるように環境を整備することにした。

その一環で、まずはソファーの殺傷力を上げる。



人を駄目にするソファは生ぬるい

あれはもともと駄目なやつが駄目になるソファだ(暴言)。

駄目でない奴も駄目にする必要がある(暴言)。




40 cm x 40 cm x 4 cm x 16個


継続中。

wrote 2014/11/06 21:29:24

Windows ゲスト VMWare 太っていく現象 解決


概要

タイトルぐぐりやすくしてみた。

っていってもアクセス解析とか1mmもやってないが。


ホストがMac OS X

ゲストがWindows8.1

という状況下で、ゲスト側のいらないファイルをゴミ箱→削除したところ、

ホスト側の容量が全く増えなかったのが発端。


助けを乞う

スクリーンショット 2014-11-04 10.23.36.png



救われる

スクリーンショット 2014-11-04 10.23.53.png


Qiita

VMWareのゲストイメージ圧縮方法

http://qiita.com/gogonosmarty/items/f13fd3f20c2fffd531d3



最終的にqiitaの記事がクリティカルヒットして、ゲストでゴミを消した分(とほかにも何かそれ以上)の容量が帰って来た。


やったぜ。


手順はQiitaのが詳しいのでサクッと書くと


・前提として、VMWare tools をゲストにインストールしておく

・ゲスト側でcommand prompt -> disk shrink 対象のディスク  を実行

という感じ。


なんでゲスト側でshrink実行する必要があるんだろ??

ちょっと興味深い。



wrote 2014/11/04 10:20:47

出、出~! BonjouriOSMacをつなぐタッチインターフェース奴


概要

iOSをマウスにするアプリケーションで、BTとかで動くマトモな操作性のやつが無かったので作った。

主にZBrushを操作する用。

https://vimeo.com/110065443


このへんが原義

http://sassembla.github.io/Public/2014:09:14%2014-40-08/2014:09:14%2014-40-08.html


コードはここ。

https://github.com/sassembla/iMousePadPre



Swift + BTLEマウス化したものは商品にしか入れないことにした。

Appleの審査に落とされるとかしたら、公開すると思う。


気づいてみたら、オープンソースにしてもそれがObj-Cのままだと、いずれ来るSwift化のタイミングで面倒くささが出るんで、

コードをオープンにしてもソンはしないと思った。


今回のこれは商品のコードとは呼べないが。


インターフェースの内容について

マウスが模倣できればよかった。


んで、マウスのボタンは最初、タッチポイントとは別々にするつもりだった。

でもそれだと使いづらくて、考えた結果、


マウスのタッチポイントから相対的な位置を別の指でタッチすると、位置によって右クリックとかを発生させるようにした。


これで、「目で見てないでもタッチインターフェースをマウスのように扱う」ことができる。


こんな感じ。


スクリーンショット 2014-10-27 22.12.30.png


要は、

画面は目で見えないけど、指の相対的な位置関係は自分の手なのでまあ分かる という。



使いづらさを分解する

最初こういうのだった。


ボタンが4つ、

四角いのはキーボード、丸いのはマウスクリック。


マウスのポインティングはボタン以外を押すことで発生。

BzRXSLcCcAEetOe.png-large.png


でまあボタン位置を下に持っていけば

「左手でボタン」

「右手でマウス移動」

ってできるんだけど、左手の負荷が最悪に高かった。


また、観てないと押せないので、困った。

というわけで現在のUIになったとさ。


動画その2

vimeoの制限のせいで画質最悪だけど、

まあ金払ってない俺が悪いのでそのうち奇麗なやつ上げ直す。

タッチ動作、左クリックと右クリック、ホイル動作も出力できる。


https://vimeo.com/110065491


ZBrushをMBAから使うための良いおもちゃができた。ちょっと満足だ。




wrote 2014/10/27 21:54:33

最高のNotificationにしような


概要

Mac OS Xで使用できるNotificationの話で。

Notification

スクリーンショット 2014-10-23 23.50.47.png

に、ボタンをつけたくなったんだけどどうやんねやろ? ってなったのとちょっとハマったので備忘録。


Yosemiteで動くかどうかは明日試す。



Notificationにボタンをつけてテストの再実行

JenkinsとかCircleCIとかでテストを実行していて、特定のテストだけ、今ちょっと実行してみたいな、みたいな

そんな時がある。 


で、まあ、どこかのテストの失敗時にこんなのが出るとするじゃない。

ボタンをつけて実行、とかやると、後からでも特定の失敗したテストだけ好きなときに実行できて便利、みたいな。

MacアプリなのでSwiftで書いてもよかったんだけどちょっと古いMacもあるんでObj-Cで。



標準的なボタン無しのNotification

スクリーンショット 2014-10-24 0.07.31.png


に、任意の文字表示でボタンをつける(閉じるボタンも着く)

スクリーンショット 2014-10-24 0.02.30.png

っていう奴を書く。


基本的なNotificationをObj-Cから出すコード

まずボタン無しを出すコードの全体が下記。


NSUserNotificationCenter *notifier;


// どこか初期化ブロック

{

    notifier = [NSUserNotificationCenter defaultUserNotificationCenter];

    notifier.delegate = self;

}



/**

 通知

 */

- (void) notifyToUserWithStatus:(int)status withTitle:(NSString *)title message:(NSString *)message {

    NSUserNotification * newUserNotification = [NSUserNotification new];

    newUserNotification.title = @"title";

    newUserNotification.subtitle = @"subtitle";

    newUserNotification.informativeText = @"message";

    

    [notifier deliverNotification:newUserNotification];

}


/*

 Macの通知センターのデリゲート

 */


/**

 notificationがタッチされた場合の挙動

 */

- (void)userNotificationCenter:(NSUserNotificationCenter *)center didActivateNotification:(NSUserNotification *)notification {

    // do something

}


/**

 アプリケーション側がdaemonとかUIを持たないアプリケーションでも、とにかくNotificationを表示するかどうか

*/

- (BOOL)userNotificationCenter:(NSUserNotificationCenter *)center shouldPresentNotification:(NSUserNotification *)notification {

    return true;

}


notifyToUserWithStatus:withTitle:message: メソッドにいろいろ叩き込むと、

ボタン無しで指定した文字要素でNotificationが出る。



ボタン付き

notifyToUserWithStatus:withTitle:message: メソッドの中身を下記のように変える。


- (void) notifyToUserWithStatus:(int)status withTitle:(NSString *)title message:(NSString *)message {

    NSUserNotification * newUserNotification = [NSUserNotification new];

    newUserNotification.title = @"title";

    newUserNotification.actionButtonTitle = @"button";

    newUserNotification.hasActionButton = YES;

    newUserNotification.subtitle = @"subtitle";

    newUserNotification.informativeText = @"message";

    

    [notifier deliverNotification:newUserNotification];

}


はいはい簡単簡単、って思ったら、実際出ない。

で、


Info.plist に下記プロパティを付け加えると出るようになった。

スクリーンショット 2014-10-24 0.11.39.png


key:

NSUserNotificationAlertStyle


value:

banner or alert or none


参考、Appleの死霊

https://developer.apple.com/library/ios/documentation/general/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html


こんな感じ。


スクリーンショット 2014-10-23 23.55.03.png

まんまNSUser.. みたいなキーで通った。

コード + 上記plistの設定で、ボタンがついたりつかなかったりそも表示されなくなったりする。


banner = ボタン無し

alert = ボタンあり

none = 出なくなる


下は alert + コード側でボタンの文字をセットしたもの。

1__#$!@%!#__スクリーンショット 2014-10-24 0.02.30.png

    newUserNotification.actionButtonTitle = @"button";

でオリジナルのボタンのタイトルを設定しているが、このコードが無かった場合、以下みたいな表示になる。

スクリーンショット 2014-10-24 0.21.42.png

で、ボタンが押されたイベント自体は、以下メソッドで取得できる。

userNotificationCenter:didActivateNotification:



ただ、Notificationの内容は、Userが設定.appとかから変更できる

参考:https://github.com/Daij-Djan/DDMountainNotifier/issues/3


ので、こうセットしたからといって完全にボタンが出せるわけでもない。



以上だが

2点問題があって、


1.一度キーを付け加えたらたとえキーを消しても最後にセットしてあった要素が効き続ける

例えばvalueを alert にして、保存、一度実行→キーごと行を消して再度実行、

ってやっても、Notificationからボタンが消えない。


これバグなんじゃねーかな。



2.ボタン付けたら消えなくなった

自動的に消えないので、ずっと画面上に表示されちゃう。

全然お手軽なUIじゃなかった。

信じてたのに!! スワイプでも消せないし。

というわけでお蔵入りした。



wrote 2014/10/23 23:50:58

エリクサーゲームズ


概要

いろんなゲーム x エリクサー

とかを考えると面白そうな気がした。

2つ以上、複数の要素を全回復にする、という要素を軸に、そのアイテムがあるゲームを作る。

エリクサーは制約として存在する感じ。



格闘ゲーム x エリクサー

レースゲーム x エリクサー

シミュレーションゲーム x エリクサー

などなど。

wrote 2014/10/04 23:59:40

座駆動LT大会にうどんの話をしに行ってきた


概要

大都会岡山っていう、香川県に向かう途中によく立ち寄る場所があって。

そこの座・スタジアムっていう映画館跡を利用した大宴会場があって。

LTしてきたのでまとめる。



合同勉強会in大都会岡山 座駆動LT大会

http://gbdaitokai.doorkeeper.jp/events/12940


なぜ今

すっかり忘れてた。

最高に楽しかったので感想はその場に置いてきてしまっていた。

あと香川に行ってうどん食べたりうどん粉買ったりで忙しかった。



内容

わたしの発表内容はこちらです。

U11n

https://dl.dropboxusercontent.com/u/36583594/outsource/U11n/index.html



当日のようすのもっともよい鑑賞方法

Togetter

http://togetter.com/li/718900



やっぱ座いいなーーーーああいう場所が都内にも欲しい。

wrote 2014/10/01 22:18:29

Unity Suddendeathon ♯2でした


概要

即死ゲームをつくろう! みたいなサドンデスゲームジャムやってた。

6時間で、とにかくプレイヤーが即死するゲームを一本を作ろう的な。


本日の即死の世界


@tori_kizi さんの落下即死ゲー。

IMG_0016.JPG

見た目全く同じですり抜けるブロックがえぐい。



@tsubaki_t1 さんの迷路即死ゲー。

IMG_0017.JPG

いろんな種類の「プレイヤーを追って殺す」のがあってよいなーと思った。


ワイの。

https://dl.dropboxusercontent.com/u/36583594/2014%3A09%3A27%2018-32-44/Suddendeathon_2_Webuild/Webuild.html

スクリーンショット 2014-09-28 3.41.00.png

落下させて殺すゲー。

タイムオーバーで未完成だったんで禁断の延長戦やった、、、


コードはこちら。

https://github.com/sassembla/Fall


バグがあるな?(迫真)



得た知見

それぞれ発表したあとに、「ここはこうやったッス」とか「この辺にクソみたいなこだわりが」とかやると大変面白かった。

楽屋時間みたいなものを今後は予定に入れてやってみようと思う。



wrote 2014/09/27 18:32:44

blueZについて


概要

iOS標準で用意されてるCoreBluetoothライブラリだとやりたいことができないので

それ以外の方法を探していて、

blueZをiOSでPeripheralとして動かせないか、という発想に至った。


blueZ

http://www.bluez.org


Linux用のBTライブラリ。Peripheralにもなれる。


gitRepoはこちら。

http://www.bluez.org/development/git/


Peripheralになるには

下記が参考になった。


http://stackoverflow.com/questions/21428446/bluetooth-low-energy-use-bluez-stack-as-a-peripheral-with-custom-services-and



wrote 2014/09/20 21:04:07

iOSをBLEマウスにするのあきらめていなかった


概要

Bluetooth 4.0iOSをマウスにするのには失敗した前回。

とりあえずMac側にサーバアプリ入れないと駄目だ、、死のう、、、


→あきらめてなかった。

本体を作り終わったら再開する。まず一度終わらせよう。


別の実装を探す準備

http://www.bluez.org/development/git/


自分のクソみたいな犯罪歴として、iPhone3GSくらいのころにBulletをタッチで動くように

書き直したことあるので、地獄のような移植作業には自信がある。


とりあえずBonjourでのアプリケーション側の実装を進めている。


iMousePadPre

https://github.com/sassembla/iMousePadPre



現在の通信方式

さっさと成果が欲しいので(というかモデリングしたいので)日和ってBonjourを使う。

ただし「同一wifi下にすべてのマシンが~」という条件からはどうにかして逃げ出す。



通信経路は以下のようになった。


・iPhoneでのBTテザリングあり

・iPadでiPhoneのBTテザリングを受ける

・MacでiPhoneのBTテザリングを受ける


この状態で、wifiとか付けなくてもMac-iPad間が接続される。

見てるか哲平、、、wifiなんていらなかったんや、、



避けた選択肢について、一応弁解しておくと、

・同一wifi内に全マシンがある場合はそれで良いんじゃない? →wifiでんち食うからキライ

→同一wifi内っていう条件が満たしにくい


・Macでwifi局作って接続すれば良いんじゃない?

→めんどいしいろんな事故のもとになるからヤダ


以上。いろんな場所であそびたい勢としてはwifiの単独ポータビリティの無さに殺意。



Bonjourでの実装

参考にしたQiitaの記事が簡潔。

あ、ただ開始時にport指定してるのがあんまり意味ないと思ったのでそこは変更した。


iOS と Mac OS X 間を Bonjour で通信してちょっと楽しげなこと

http://qiita.com/feb19/items/da07d96619acb933a3c3


差分

https://github.com/sassembla/iMousePadPre/blob/master/ServerPre/ServerPre/AppDelegate.m#L41


切断周りに何の対処もしてないのでそのへんあとでやる。



残りの実装

Bonjour経由での通信にBlocks使えるハンドラが出てるので、データの受け渡しは楽。


将来BLEのコード書き直した時用に出力 = iOS側を調整する必要があるけど、

その場合は出力側のみ変更すればいいので、データのコーディネートする箇所だけを

独立させておけば改修は簡単そう。

マウスのコードの参考

http://www.xappsoftware.com/wordpress/2013/07/08/how-to-simulate-mouse-movement-and-clicks-on-mac-os-x/


キーイベントの参考

http://ianyh.com/blog/2013/06/05/accessibility/


このへんのトリガーをNSDataに固めて受けて解答して着火、ってやればOK。

成果物がこちら。


iMousePadPre

https://github.com/sassembla/iMousePadPre


wrote 2014/09/20 17:51:31

BLEでiPadをMacにマウスとして接続する気だった、今は反省している


概要

ZBrushやっててさくさく削りたくなったので、

iPadでキー+マウス操作を行い、Macに送り込むツールを自作することにした。


以前作った、「wifiでディスプレイの一部をiPad上に切り取って筆圧付きペンで部分ペンタブを実現する奴」とは異なり、

・サーバアプリケーション無し

・アスペクト比固定

みたいな省力版が作りたい。


というかやりたいことは快適なモデリングなんだよ。



要件定義、設計

ソフトウェアの要件定義とジェスチャの設計としてはこんな感じ。


Pasted Graphic 3.tiff


Pasted Graphic 2.tiff


Pasted Graphic 1.tiff

Pasted Graphic.tiff

はい、描いた人にしかわかりませんね!



調べるその1 サンプル

サンプルを探す。

安定のgithub検索

https://github.com/search?utf8=✓&q=iOS+ble&type=Repositories&ref=searchresults


以下がそのまま動かせた。

https://github.com/khr128/BTPeripheralIPhone

んで、Peripheralって何って話が始まる。

以下が参考になった。

http://reinforce-lab.github.io/blog/2013/01/21/ios-ble-introduction/


調べるその2 規格と仕様について

やりたいこととしては、

BLE使って、iPadをMacにマウスとして認識させる

なので、以下のような話が始まる。


・まずBTマウスはどうやってMacにつながってるのか

→BTLEマウスがあるんなら調べなくてよさそう


・BTLEマウスってあるのか

→あった

・Macでドングル無しでつかえんの?

→使えた。キャリブレーションめっちゃ怪しい。


・iOSをマウスとして接続できるのか

→MacをCentral、iOS側をPeripheralにできる!

→既存でできてるマウスがあるんだしできるのでは?

→というわけであとは試してみることに。



実装

死霊++

Bluetooth のプロファイルについて調べたことのまとめ

http://d.hatena.ne.jp/shu223/touch/20140109/1389216052


CoreBluetooth

Eng

https://developer.apple.com/library/prerelease/ios/documentation/NetworkingInternetWeb/Conceptual/CoreBluetooth_concepts/CoreBluetoothOverview/CoreBluetoothOverview.html#//apple_ref/doc/uid/TP40013257-CH2-SW1

Jp

https://developer.apple.com/jp/devcenter/ios/library/documentation/CoreBluetoothPG.pdf

で、HID over GATT Profile (HOGP)について、以下のサービスが必要。


Hunan Interface Device  Service (0x1812)

https://devzone.nordicsemi.com/documentation/nrf51/4.1.0/html/group__ble__sdk__srv__hids.html


と、

Device Information Service (0x180A)

https://devzone.nordicsemi.com/documentation/nrf51/4.1.0/html/group__ble__sdk__srv__dis.html


と、

Battery Service (0x180F)

https://devzone.nordicsemi.com/documentation/nrf51/4.1.0/html/group__ble__sdk__srv__bas.html


1812とか、それぞれのAssignedNumberは、下記に書いてあった。

https://developer.bluetooth.org/gatt/services/Pages/ServicesHome.aspx


→Macへの接続状況をしらべてみたところで、ServiceのIDを1812系に変えたら、

Serviceのadd時に

The specified UUID is not allowed for this operation.

というエラーがでた。なるほど使っちゃ駄目と。



詳しく書くと以下の箇所でエラーが出る。


- (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral {

    

    switch (peripheral.state) {

        case CBPeripheralManagerStatePoweredOn:{

            CBUUID *serviceId = [CBUUID UUIDWithString:@"00001812-0000-1000-8000-00805F9B34FB"];

            cbService = [[CBMutableService alloc] initWithType:serviceId primary:YES];

            [cBPManager addService:cbService];// <- このあとでおこ The specified UUID is not allowed for this operation.

            break;

        }

            

        default:

            NSLog(@"hereComes");

            break;

    }

}


はい。

駄目だそうです。


ちなみにiOSでCoreBluetoothを使ってPeripheralになろうとして怒られる AssignedNumber の一覧は無かったので作った。

こんな感じ。


ecbarw.png


1__#$!@%!#__ecbarw.png


2__#$!@%!#__ecbarw.png

dead | alive

3__#$!@%!#__ecbarw.png

Alert Notification Service

org.bluetooth.service.alert_notification

0x1811

ok

Battery Service

org.bluetooth.service.battery_service

0x180F

denied

Blood Pressure

org.bluetooth.service.blood_pressure

0x1810

ok

Current Time Service

org.bluetooth.service.current_time

0x1805

denied

Cycling Power

org.bluetooth.service.cycling_power

0x1818

ok

Cycling Speed and Cadence

org.bluetooth.service.cycling_speed_and_cadence

0x1816

ok

Device Information

org.bluetooth.service.device_information

0x180A

ok

Generic Access

org.bluetooth.service.generic_access

0x1800

denied

Generic Attribute

org.bluetooth.service.generic_attribute

0x1801

denied

Glucose

org.bluetooth.service.glucose

0x1808

ok

Health Thermometer

org.bluetooth.service.health_thermometer

0x1809

ok

Heart Rate

org.bluetooth.service.heart_rate

0x180D

ok

Human Interface Device

org.bluetooth.service.human_interface_device

0x1812

denied

Immediate Alert

org.bluetooth.service.immediate_alert

0x1802

ok

Link Loss

org.bluetooth.service.link_loss

0x1803

ok

Location and Navigation

org.bluetooth.service.location_and_navigation

0x1819

ok

Next DST Change Service

org.bluetooth.service.next_dst_change

0x1807

ok

Phone Alert Status Service

org.bluetooth.service.phone_alert_status

0x180E

ok

Reference Time Update Service

org.bluetooth.service.reference_time_update

0x1806

ok

Running Speed and Cadence

org.bluetooth.service.running_speed_and_cadence

0x1814

ok

Scan Parameters

org.bluetooth.service.scan_parameters

0x1813

ok

Tx Power

org.bluetooth.service.tx_power

0x1804

ok

User Data

org.bluetooth.service.user_data

0x181C

ok



最終的な結論は、「iOSをPeripheralにしてHOGP(とあといくつかのAssignedNumber)を使うのは無理。」



おまけ

Macに限定するならこっちでつくるかなあ、、

Bonjour

http://qiita.com/feb19/items/da07d96619acb933a3c3



wrote 2014/09/14 14:40:08

o #ScalaMatsuri x #ScalaMatsutri と感想について


概要

なぜ人はhashtagを間違えるのだろう。


ScalaMatsuri 

http://scalamatsuri.org/en/


に行ってきた。



特筆すべき2、3のこと

・言語を開発する人と利用者側としての原理主義的なものの隙間がみれてよかった

・アンカンファレンスでsbtについて聞けたのよかった

・Twitterのタグ間違い過ぎ


言語を開発する人と利用者側としての原理主義的なものの隙間がみれてよかった

主に小田好先生まわりのお話として、「いや~こういうつもりでつくってるねんで」みたいなのが

ダイレクトに聞ける環境だったのはよかった。主に2日目のアンカンファレンスの内容として、居合わせられてよかったなーと思う。


なんでも原理主義がこわくて、

このへんはずっと前にあった「こわくないScala」でも感じてたことだったんだけど、

言語作っている人はどう考えているんだろう、みたいな疑問があって、

例えば端的な答えとして、小田好先生が

「ScalaはFunctionalとOOPのどっちの特性も持つ初の言語なので、新しい問題にぶちあたるのは当然」

みたいなニュアンスのことを言っていたと思うんだけど、


これって原理主義どうしのV.S.みたいなものもひっくるめて「ああーきちゃったねぇー」みたいにとらえられているんだなあと思って、


まあこれ聞いて「固っ苦しい感じじゃないんでよかったなー」と安心しました。

別に安心/不安だからってどうこうあるわけじゃないけどさ。


元来、用途は使用者のものだし。



アンカンファレンスでsbtについて聞けたのよかった

特に1日目の終わりあたりで、sbtについて飲みながら井戸端っぽい感じで話をしていたのだけど、

2日目にて「sbt被害者の会」なるアンカンファレンスの内容が成立したのには心底驚いた。


まあ名前はギャグなんだと思っているし実際本当にナーバスな内容では無かった。


で、まあTypeSafe社でsbtに関わっている方々 + 参加者の皆さんで、sbtについて順繰り話をしていくことに。

とりあえず自分は以下の観点でだけ発言したつもり。


以下は当時のメモ(質問の番が来る前にガーーっと手元でまとめようとしたもの。支離滅裂感あるけどそのまま掲載。

太字の部分は、実際に何か話をしてからの加筆内容をメモったもの。括弧内は自分の感想。

スクリーンショット 2014-09-08 23.55.57.png

で、当日 @seratch (@seratch_ja) さんが書き纏めてくれていたメモがこちら。

https://docs.google.com/document/d/1uhBC1sRj6yWUVKOs4nWEfeTm6gRL-SUTtMTQ57FHTsU/edit



参加してぶちまけて、それに対して真摯に話を聞いてもらったりアドバイスをいただいたりしていく中で、

自分がすごく誤解してたこととして、

・前提から難しいと思われていない

というのがあって、あーーこれはしまったなーと終わってから思った。


自分が言った(つもりで伝わってなかったであろう)言葉としては、以下のあたり。


「現在のデザインでなければいけない? めっちゃ難しく解決できるようになっている気がする」

「なんでも書けば解決できる、という現在のデザインが、その難しい方向を助長してる気がする」

「難しいことできなくすることでできる事もあるんじゃないのか」



我ながら「まあなんて失礼な。貢献しなさいクソ野郎が。」みたいなこと言われそうな内容を言ったなあ。

アンカンファレンスでしかも「sbt被害者の会」なんて名前でなければ絶対に言わなかったと思う。


得られたフィードバックとしては、今後こういうのつくろうかなー、と思うだけのものがあった。

ようはモチベーション得られたぜ!という感じ。

それと、おまけで末尾に書き足したけど、「こわい」について、間接的だけどわかった気がした。



あとついでにsbt serverについてちらっと聞けたのもよかった。



Twitterのタグ間違い過ぎ

たとえばTwitterのMac クライアントで以下のような状態になった

b.pnga.png

Suggestに大量の間違いhashtagがどんどんでてくる

なんだscakamatsuriって、、

みたいなのに気づかずにTwしてしまうことがままあって、


「だって補完ででるんだもんしょうがないじゃない!!」

みたいな気になるが、


このへんのミスを減らすために何ができるんだろう、みたいな課題が自分的にスタックされたのだった。



そんなScalaMatsuri。



感想とおまけ

ScalaMatsuri、とても快適で、とにかく快適で、快適だった。


ごはん出るし、

自分が選んだルームのトピックには必ず1つ以上の驚嘆と得るものがあったし、

英語で~みたいなものに対しても共感できたし、

(このへんはスタッフの方々の苦労が本当に忍ばれるし、また今回の事を経て得たものもたくさんあると思う。)


運用をなさっていた皆様、ありがとうございました。

めっちゃ快適でした。


自分が感じたScalaでの「こわい」に対する答え

おまけで、なんとなく空気感的に答えを得たので、

Scalaにおいての「こわい」みたいなのの感想を書いておく。

特にsbt周りの話がそれを想起させたので。

こわくないScala の vol 2もあることだし。

恐い、怖い、こわい。

時々いろんなところで聞いてた(最近はあまり聞かなかった言葉)なんだけど。


こわい = こわさ = 

「それを知ってるのが当たり前」っていう態度が、たとえそう思ってなくてもどうしても素で出ちゃうこと なのかと。勝手に解釈した。


ここでいう「こわい」、っていうのは、Scala(とsbt)の知識に対する、強迫っぽい

「ついてこれなきゃ駄目っぽさ」を具現化した感情なのだと思う。




誤解が怖いので書いておくと、Scalaに「強迫観念的に、使用者に知識を求める」みたいな側面は無いと思っている。

特に今回の小田好先生の話で、それが明確に観測できた。



「それを知らなくてもかまわないよ」、って言う言葉が出てこないことで、脅迫っぽく見えちゃって、結果として

「こわい」っていう言葉が使われるのかなーと。


まあそれだけで、何でもないんだけどな。

wrote 2014/09/08 23:23:06

🍣現状確認会


概要

shi.png

http://www.zusaar.com/event/9467003


こちらからの確認内容の共有です

スクリーンショット 2014-09-02 19.40.36.png

スシゲートの人間として

完了するわけにはいかないな。






スクリーンショット 2014-09-02 20.04.45.png






というわけで

過去4回、おすしやさん 「禅」に向かった旅の記録を手短に共有させていただきます。


前提

☆ 予約不可

☆ 開店前から並ぶ

開店の瞬間にはすでに10組ほど並んでいる



要件定義

魂が回転寿司 「禅」に無事デプロイされること。

対象のアドレスは

2-1-29 Higashicho, Odawara, Kanagawa 250-0003



「回転 禅」で検索。

スクリーンショット 2014-09-02 20.23.24.png



プロトコル

小田急 RTTP(ロマンストランスポーテーションプロトコル)を使います。

from 新宿駅 to 小田原駅


(往路)新宿 -> ロマンスカー -> 小田原 -> タクシー -> 禅


(復路)新宿 <- ロマンスカー <- 小田原 <- タクシー <- 禅



よい時間

新宿駅で、朝 9時30分発のロマンスに乗ると、


小田原駅の時点で10:30前後。


禅に到着する頃には開店20分前くらいなので、最小の並びで食えてベストです。


Quota

ロマンスカー 片道: ¥870(特急料) + ¥1,150(乗車料) = ¥2,020

巡礼費:不明(¥6000~一万円いかないくらい)






おまけ



🍣へのコミットを表すSushitributeという日記をつけるのはどうでしょうか。

Sushitoribute.png


以上です。


wrote 2014/09/02 19:39:08

ZBrush学ぶ


概要

モデリング楽しいね! っていいつつ、自分が使えるのBlenderMetasequoia(Winのみ)だったので、

もうちょっと主観的に楽にできることを増やして遊べるようになるために、ZBrushやってみる。

現状 2014/11/02 1:46:09

スクリーンショット 2014-11-02 1.57.42.png



起動時


lightboxが邪魔なので起動時は表示されないようにする

Preferences > Lightbox > Open At Launchを押してオフにし、Preferences > Config > Restore Custom UI を押す。



基本操作系


回転

右クリックドラッグ

shiftを足して制限付き



ズームイン、アウト

右クリック + Ctrlドラッグ



オブジェクトの移動

右クリック + altドラッグ



オブジェクトを全画面に収まるようにカメラ調整

Fキー



ブラシ一覧の表示

Bキー

文字打ちによる絞り込みがあり、1文字打った段階で、2段階目の候補に対していろいろアルファベットが振り分けられるので、 Sublimeのやつとは違う感じ。



Right Shelfに選択したメニュー項目を表示

alt + クリック



ブラシのadd か、 sub の切り替え

ctrl



スムーズブラシへの切り替え

space


ブラシのサイズ調整

Sキー



マスク系


マスクペンでのマスクの作成

ctrl + オブジェクト上からオブジェクトをドラッグ


マスク部分解除

オブジェクト上で ctrl + alt + ドラッグ


矩形でマスク選択

オブジェクト外からドラッグ


マスクの反転

オブジェクト外でctrl + クリック


オブジェクト外でctrl + ドラッグで、解除


すべてをマスク

ctrl + A 



Visible


visible範囲を限定

オブジェクト上でctrl + shift + ドラッグ


解除

オブジェクト外でctrl + shift + クリック


反転

オブジェクト外でctrl + shift + ドラッグ



操作系2


下絵

Draw > Front-Back > Map1 > Import とかで入る。



開いてすぐに思うこと

最初のオブジェクトどうやって出すんだろ。

スクリーンショット 2014-09-01 23.31.10.png →まずあり方として、Tool の中に、現在選んでいるツールが表示されている。

ここに気づくと、

・Tool の中の左上の項目は現在選ばれているアクティブなツール

・ツールっていうか素材の意味な

という感じに思考が進んだ。

なるほど。

で、Current Tool を選ぶと、ウインドウが出てきたのでZSphereを選ぶことができた。



リセット

なにもかもリセット:

Preference > Init ZBrush

Edit外してDrawだけのとき置いちゃったものリセット:

メニュー > Layer > Clear



ZSphereでのモデリング

Editモードでぽいぽい足せる。

足せない場合、メニュー上部の Add と Sub が両方消えてることがあった。

っていうか両方消せるんですね。便利(?)

多分何かの拍子にショートカットを押しちゃってるんだろう。


Tool > Make Polimesh 3D で変換すると、Divideを押すことができた。

このあたりの状態遷移は一度図にすると助かりそう。


ZSphereでの操作モードについて

MoveとかScale、Rotateが使える。

Sphere単位で動かせるので便利。

スクリーンショット 2015-07-09 0.15.10.png


スクリーンショット 2015-07-09 0.19.01.png



ZBrushからSkinを作る

Aキーでプレビューがでる。が、でる前に死ぬことが何回かあったので死ぬ前にセーブしよう。

Tool > Adaptive skin > Make Adaptive Skin で作れる。


シンメトリーな編集

Xキーを押すと、対照移動するポインタが出る。

出無い場合、、、どうなってるんだろうな、、

→今見ている視点の軸がおかしい。気付くのに時間がかかった。

視界に対して奥行き方向にカーソルが出てる。たぶん。

Transform > Activate Symmetry で、現在対象になる軸がわかるのでそこでチェック。



操作系3

サブツール

オブジェクト(ツール)を複数に分割したもの一式。

Extractとかで作り出す。


パーツ分割(Extract)

マスクする > Subtool > Extract > accept でマスクした範囲を別のツールとして分離できる。



ZBrushの概念で何だろうって思ってたこと

ZBrushにおいてTool って名前で名前で扱われるのはまさに「編集対象」とそれらのコレクションのことで、

おま、、それなんで、、Toolって名前にしたし、、、とかまだ同調できてない事柄がある。


ZBrusherさんになんでそういう概念なのか聞いてみたい。

割り切ればそういうものだと納得できる程度には一貫してる気がする。


困ってること

GeometryのDivideが出ないことがある?

ZSphereでSkin作成→Divideができない。なんでだろ。

→ そもZSphereを変更できてないっぽ。Preview で落ちるとかよくある感じなのでセーブ必須。


こうなっちゃったらどうするの?

スクリーンショット 2015-07-08 22.01.39.png

カーソルだけ暴れてる状態。

消すのは、Layer > Clearから出来る。

で、

設定が2.5Dモードになっている + シンプル・ブラシを選んでる場合こうなっちゃうそうなので、そのへんを調整する。

→Tool > 左下に写ってるのがCurrent Tool

んで、こいつを変更する。3DMeshesの中身だったらなんでもいい。

dasd.png



キャンパスにオブジェクトがいっぱいでる

次にこのモードになる。困る。

一個でいいからなにかを置いて、Tキー or Edit ボタンを押す。やったぜEditモード。



プリミティブなオブジェクトが置かれているのでモデリングできない

Tool > Make Polimesh でポリメッシュ化する。

スクリーンショット 2015-07-08 22.40.39.png


Devideの意味

ZBrushは複数の解像度のあいだを行ったり来たりできる。

最終的なポリゴン数に関しては、わりと「あとで考える」的。

で、

スクリーンショット 2015-07-08 23.02.35.png

Divideを行うと、

・元のポリゴン分割のモデル

に加えて、

・細かくしたポリゴン分割のモデル

を新たに作り出す。

んで、この新旧のモデルをそれぞれ保持する。

shift + Dで下のDivideに戻る

D + 上のDivideがある場合上のDivideに移動

control + D + 現在が最高位のDivideのとき、上方向のDivide実行



モードの話

形状編集を行うEditモードと、

移動とか拡大縮小とかを行うMove, Scale, Rotateモードがある。



Moveモード

スクリーンショット 2015-07-08 23.57.50.png



Scaleモード

スクリーンショット 2015-07-08 23.59.27.png



Rotateモード

スクリーンショット 2015-07-09 0.01.41.png


1__#$!@%!#__スクリーンショット 2015-07-09 0.01.41.png



2__#$!@%!#__スクリーンショット 2015-07-09 0.01.41.png



Fキーで現在Activeなサブツールを視界の真ん中に

便利。もう一度押すとサブツール内で最大のものにフォーカスする。



Tool > LoadToolから物事を扱うようにすると楽

Ztlのみを扱うと楽なのではっていう話。

ZProjにはテクスチャとかも入るので、そっち使うのが便利っぽいんだけど、履歴とかも入ってクッソ重くなっていくのでモデル (=ツール)はZtlのみで保存するといいのでは?っていう。

Tool > LoadToolとかSaveとかでモデル=ツールを扱うと、部品を個別に読み込み直したりとかができるので、便利かもしれない。


落っこちたら今まで作ったモデルはどうなるの!?

LightBox > QuickSave の中に入ってるかも。

もしくは、

LightBox > Brush > Recorded_Document フォルダとか。



Tool > SubTool

モデルをレイヤー分けみたいな感じで持っておける。

んでNキーでSubToolの一覧(ActiveなSubToolは含まれていない)を出すことができる。



SubToolのアクティブの切り替え

上下キーでできる。

ctrl + 上下キーで、ActiveなSubToolのリスト上での位置を変えられる。

また、キャンバス上でalt + クリックで、ActiveなSubToolを切り替えられる。



SubToolのDivideLevelをまとめて切り替え

Tool > SubTool > All Low or All High で、すべてのSubToolがそれぞれ保持しているDivLevelを一気にいじれる。


SubToolのコピー

Tool > SubTool > Duplicate でActiveなSubToolのコピーが作れる。


別のモデルをSubToolとして読み込む

Tool > SubTool > Insert で、外部のモデルを現在のモデルへと、SubToolとして読み込むことができる。



パースペクティブの比率を変える

地味にやりたいことがある。

Draw > PerseP > AngleOfView で変更可能。



shift + Pでフロアの面を表示

Floorボタン上のx,y,zボタンをクリックすると、対応する床がキャンバスに表示される。



LocalTransformで回転軸制御

LocalTransform ボタンで、キャンバスでのモデル回転の際の回転軸の固定ができる。

ボタン上のxyz, y, zとかそのあたりを選択すると変わる。



PolyFrameでポリグループの区分けが視覚化できる

LineとかFillのボタンがあり、それらを押すと細かいオンオフができる。



Transparentボタンで編集してるSubTool以外を透明に

ActiveなSubTool以外を透明にする


Ghostボタンとの組み合わせで、現在編集中「ではない」厚さのあるパーツを表示させながら、現在Activeなパーツを編集できる。


Solomodeをオンにして、ActiveなSubToolだけが表示される

SubToolのリストの目玉マークいじるより楽に可視状態が変更できる。


ActiveなSubToolにテクスチャを貼る

Tool > TextureMap で、左上の四角をクリック > 出てきたウィンドウの左下の方のImport ボタンから画像が貼り込める。


イテレーション

繰り返しで作業できるようになってきた。

・ZSphereでモデルの素体を作る

・板ポリ置いてTransform > Transparent とGhost オフで、いい感じに編集

未経験領域

・ダイナメッシュ?



簡単な背景図の作り方

Tool > CurrentTool > Plane3Dを選択

Tool > TextureMapを選択

左上の四角をクリックして読み込む画像を選択

左下のImportを選択

テンプレートになる画像を読み込む

Tool > SubTool > Duplicateで複製

複製したパネルのTool > Deformation > Rotate をy90

複製したパネルのTool > Deformation > Offset をz-100

複製する元のパネルのTool > Deformation > Offset をz+100


そんでこんな感じになる。

スクリーンショット 2015-07-21 23.22.45.png


実際に作成する対象としてSubToolをInsertして使う。


wrote 2014/08/31 21:46:00

俺的新手法でAtomのアイコンを変える


概要

Atom.io のアイコンが嫌いだから変えて使うぜ!! って話をしてて、

やってみたらアイコンの変え方がちょっと特殊だったよって言われたんだけど、


過程でアイコンを変更する新しい方法見つけたのでまとめる。



AtomのアイコンはResources/(中略)/icon名.icns を変えるだけでは一部変化しない

Mac用のアプリケーションのアイコンを変更するのであれば、

アプリ(X.app)を右クリック > パッケージの内容を表示 で、アプリケーションフォルダの中身のアイコンのファイルを変更することで対応できる。

具体的な前科はこのへん。

http://sassembla.github.io/Public/2013:01:12%2021-08-16/2013:01:12%2021-08-16.html



んで、どうやらAtomのやつはこの方法だけだと駄目だそうで。

Dock内のアイコンほか、一部のアイコンが変化しないらしい。

で、解決策を考えたいねーって駄話してる中で、あたらしい方法を見つけた。



新☆アイコンを変更する方法

1.アイコンを変更したいアプリケーション.appを右クリック→情報を見る

スクリーンショット 2014-08-25 15.51.38.png

2.コレにしたい!というアイコンを用意

.icnsファイルであればOK。

スクリーンショット 2014-08-25 15.57.51.png


3..icnsファイルを、1.で開いた情報ウィンドウの下記の場所に放り込む。D&D。

1__#$!@%!#__スクリーンショット 2014-08-25 15.51.38.png

で、めっちゃ簡単にアイコンが以下の範囲で反映された。

わ あ 。 楽 ゥ 。

スクリーンショット 2014-08-25 16.14.28.png



結果がこちら

・Dock内

スクリーンショット 2014-08-25 15.35.40.png


・Finder内

スクリーンショット 2014-08-25 16.20.09.png

・あとこことか

スクリーンショット 2014-08-25 16.09.51.png



おまけ

特にAtomに関して、下記の拡張子のファイルのアイコンを変更する特性があって、

.js とか .css のアイコンの見た目が変わる。


そのアイコンは、Atom.app の中にある。


Application/Atom.app のフォルダ内の

Contents/Resources/file.icns を変更すれば変わる。

スクリーンショット 2014-08-25 16.37.56.png

正直、前提として変更しないでほしい感じではある。



今回試したもの

こちらの方が作ったアイコンが気に入ったのでうれしさがある。

https://dribbble.com/shots/1441364-Atom-Icon


wrote 2014/08/24 22:16:31

Unity、C♯でXcodeのプロジェクトを改変する奴


概要

XCodeEditor-for-Unity というのに関してつぶやいてる方が居たので、使ってみた。

Unityが吐き出すXcodeプロジェクトにいろいろ書き込む奴。

最初、XcodeでUnity用の.csのコードとかを編集するのを可能にしたのか?! と戦慄したんだけど、違った。

よかった、狂気に魅せられた人は居なかったんだな、、!!


XCodeEditor-for-Unity

オリジナル

https://github.com/dcariola/XCodeEditor-for-Unity


4.5で動くようにちょこちょこ手を加えられている方のフォーク(プルリクマージされるといいのに、、)

https://github.com/kyubuns/XCodeEditor-for-Unity


で、せっかくなのでそのまま動かせるサンプル込みのフォークを作った。

こちら。

https://github.com/sassembla/XCodeEditor-for-Unity



何ができるのか

PythonでXcodeのプロジェクトにいろいろやるやつあるじゃないですか、アレ。ほらアレ。


pbxproj

https://github.com/kronenthaler/mod-pbxproj

これと同じようなことができそうな感じ。

pbxproj と比べてなにがうれしいかというと、上記をつかうにはPythonのスクリプトを書く必要があって、これがいろんな要因でいい感じに妖刀化するので、

そのへんをせめてC♯でなんとかできないかなーというあたり。



妖刀化する要因

Unityの仕様上、拡張子無しの PostprocessBuildPlayer ファイルを作ったらそれが使用されるんだけどさ。

http://docs-jp.unity3d.com/Documentation/Manual/BuildPlayerPipeline.html


こいつの中で、上記のpbxprojを使ってXcodeの書き換えとかよくやるんだけど。


以下の要因で困ることが多い。


・サードパーティーのやつが使ってて、殴り合うのが面倒くさい(っていうか使う側のコト考えたらよォーーー使わねーーのが優しさなんじゃネェーかァーー? ァァーー?

・コンパイルに巻き込まれないから全体像が見にくい

・ログ出ししにくくて失敗をフックしづらい


このへんがC♯で済めば、まあUnityの機構との親和性でだいたい解決できるし、

悪手を生成しないで済むようになるよね。


という。

サンプルを使ってiOS向けのビルドした奴のビフォーアフター置いとく

Before

1.png



After

2.png


Servicesにちゃんとlibsqlite3.dylibのリンクが入りましたねっていう。




wrote 2014/08/23 19:31:21

Unity アセットで外部エディタと連携する裏側


概要

夏だ!! アドベントカレンダーだ!! ということで

Unity アセット真夏のアドベントカレンダー 2014 Summer!

http://unityassetjp.doorkeeper.jp/events/12843


先日はyandoさんによる「Detonatorと爆発の未来」でした。

本日は8/4 の記者、sassembla がお送りします。



本題

Unityでコード編集するときに使ってる、自作のAssetがありまして。

今回はその裏側で、こんなテクニックを使ってるよー、みたいなのを紹介する。


肝心のAssetはこんなのです。 Unity と Sublime Text を連携するやつ。

スクリーンショット 2014-08-03 14.39.03.png


AssetStoreに上がってるので良かったらどうぞ!

http://u3d.as/content/sassembla/sublime-socket-asset/4SP

コンパイルエラーをエディタ上に表示したり、

ログをコード上の発生箇所に時系列でマッピングしたり、

プロジェクト完全依存な補完出したりできる。


このAssetは Unity Editorと、連携用のUnityAsset(上記のやつ)と、外部エディタ、そして外部エディタ内で動くプラグインで実現されている。

主に次のような機能で、Unityと外部エディタの連携を実現している。


1.Unityと外部エディタを接続する

2.Unityにコード全体をコンパイルさせる

3.Unityに外部プロセスから情報を送り込む

4.Unityからコンパイル時の情報を引き出す

5.Unityからコード補完時の情報を引き出す

6.Unityから引き出した情報をもとに、エディタに働きかける

それぞれ作ってておもしろかったポイントがあるので、順に書いていく。



1.Unityと外部エディタを接続する

MonoDevelopと違って、Unityが提供しているアタッチ系の機能を使用していない。

WinとMacで違ってて大変うっとうしかったためだ。リバースエンジニアリングに近かったし。


というわけで、Unityの力を借りず、接続にはWebSocketを使っている。

図にするとこんな感じ。

スクリーンショット 2014-08-03 16.37.51.png


左 Unity + SublimeSocketAsset がwsクライアントで、

右 Sublime Text + プラグインがwsサーバになっている。



なんでUnity + アセット側がwsクライアントなの?


やんごとなき理由があった。


・Unityのエディタはコード変更の度に毎回全体をコンパイルする = ゲームコードもエディタもコンパイルされ直す -> サーバになれない

・wsだったら双方向同期/非同期で通信できる

・Mac/Winとかで統一的な方法が欲しい

・別サーバで動かしているUnityを使役したいみたいな欲がある(リモートコンパイラ)

みたいなニーズと理由があったため。



特にサーバになれない理由を、もうちょっとちゃんと紹介する。

根本的なところは、Unity Editor が持つコードコンパイルの構造にある。



Unity Editor の適当なコンパイル構造は次のような感じ。

スクリーンショット 2014-08-03 16.57.48.png

Management Layer (正式名称は知らない)

UnityでのC#コードとかのコンパイルほかを管理しているレイヤ。appとかexeとして実行されているコア。


Editor Script Layer 

/Editor 名称のフォルダ以下、エディタのパーツとしてコンパイルされるコードが居るレイヤ。


Game Script Layer 

ゲームのコードとかが居るレイヤ。


★この図はいろいろ端折ってあるので、詳しくはここをみるといいと思う。

http://docs.unity3d.com/Manual/ScriptCompileOrderFolders.html



Editorのレイヤには、/Editor フォルダ名で置いたコードをコンパイルする規約があるんだけど、

言い換えれば毎回Unityのコンパイルに巻き込まれる。

これはゲームスクリプトのレイヤのコンパイルが発生しただけでも、Editorから再度コンパイルされることを指している。


別に悪いことじゃないんだけど、外部との接続を行う際、ここがネックになる。

コンパイルが走る度に、通信をしていたプロセス自体がぶっ殺されて新たにコンパイルされて、コネクションが途切れるためだ。


だれも生き残らない。



で、これは仕組みでどうこうできるものでもなし、流儀だし、何かするのが悪手に思えたので、

できるだけ再接続しやすい、切断を考慮にいれた通信方式+形態は無いか? という観点から、

ぶっちぎれ易い方/にくい方を区別して設定できて、

再接続がスムーズにいくようにデザインされてて、

かつ規格として実装流通が多いもの、としてwsを採用した向きが強い。


Unityがエディタ部分のコードをコンパイルした後、自動的に Sublime Text が動かしているwsサーバへと接続される。


もしリデザインする機会があったら、wsの代わりにMQTTを使う。オーバースペックか、、

(Sublime Textのプラグイン側には実験中のリポジトリがある。



★ちなみにこうやってみるとEditor -> Gameと順次コンパイルしているように見えるが、

実際にはEditor レイヤのコード + Game レイヤのコードを纏めた上でコンパイルしているので、

Editorレイヤのコンパイルが終わったら、Game側のコードのコンパイル前にPrecompile処理を仕掛ける、みたいなのはできない。


強制的にPrecompileする処理は可能なんだけど、どっちにしてもコンパイル後に動き出す感じになる。

てことはそれ無限ループするんじゃね?という感じ。



2.Unityにコード全体をコンパイルさせる

接続が確立された Sublime Text エディタでの保存処理をトリガーにして、

Unityにコンパイルを実行させることは、実はめっちゃ難しかった。

というのも、公式な手段が無い。

Unity Editor には、Editorに表示させたメニューからコードを変更させたり、

特定のコードをコンパイルさせる手段も存在している、、のだけれど、


これらは Main Thread と呼ばれる、Unity Editor ががっちり抱えている Thread からしかコントロールできない。

で、Unity Editor 外部からそれら Main Thread に合流してコンパイルを実行する、みたいな処理は存在しない。


ので、とてもDirtyなのだけれど、

Unity.app/exe へとフォーカスを移すと、Unityはコンパイルを始める

という事象を利用している。

スクリーンショット 2014-08-03 17.46.25.png

まったくもってバカバカしい悪手なんだけど、これが一番案配がよかった。


このへんはさすがにプラットフォームごとに互換性が無かったので、同じインターフェースで動くようにコマンドラインツールを用意した。

Mac用

https://github.com/sassembla/SwitchApp

Win用

https://github.com/sassembla/WinSwitchApp


もうちょい正しくマシな手段ができないかなー、と思っている。



ちなみにこの手段を使う上でのMonoDevelopでのビルドとの差異はかなり存在していて、


・MonoDevelopは Unity Editor が生成した.slnファイルを使用することでコンパイルパスとかリソースをプロジェクトに組み込んでいて、

MonoDevelopのコンパイルは、Slnを通じてUnityのライブラリのパスとかを使って実行しているに過ぎないので、

Unityでコンパイルしたときとは異なる挙動になる。(まあ問題がある程とは思ってないけどもんにょりする)

・上記のフォーカス動かす方法だと、そもUnity Editorに直接コンパイルを命令しているので、

Unityそのもののコンパイルがそのまま実行される形になる。


この際、assetの読み込みなどに関連する情報も出力されるため、外部に対してより多い情報や処理を持ち出すことができる。

そのかわり、単純にコンパイルしてる訳ではないので、重い。


で、Unity 4.3? 以降だと、コードのhash値かなにかに差分がないとコンパイルされないようになったので、

コメント内のタイムスタンプのみを更新するファイル、とかを使って、強制的にコンパイルが発生するようにしている。

それ以前だと、保存した時刻をみてたみたいだ。


うーんまあこれも悪手。カットできるようにはしたけど。



3.Unityに外部プロセスから情報を送り込む

wsでの接続を介して、Sub Thread 扱いでSublime Text -> Unity Editor への入力を実行できる。


結果として Sub Thread でのUnity Editorのコード実行になるので、

APIの内容によっては、Main Thread からしか呼べないよ! 的なエラーが発生する。


そのため、Main Thread でしか動作できないスクリプトは必然的に全く使えない。



これが、Unity Editor のGUIに関わるコードなら納得できるんだけど、そうでないにも関わらず Main からしか呼べない、みたいなのが結構ある。

GetPath系とか。



また、Sub Thread で来た入力を、そのまま Main Thread へと合流する手段がない。

エディタで動くコードなので、Coroutineでなんとかする、みたいな合流手段も使えない。


下図のような感じ。

スクリーンショット 2014-08-03 20.57.02.png

このへんは割と設計全体に関わる感じになる。



Main Threadでしかできないことを Sub Thread で行うことはできないが、


Sub Thread でも使いたい、Main Thread Method Depend なパラメータがあったら、

Main Thread で実行される InitializeOnLoad 時に取得してstaticなパラメータに入れておくことで、

Main Thread でしか取得できないパラメータへのアクセスが可能っちゃあ可能になっている。



ただ、WebSocketでの入力を、Unityのコンパイル中に受けると、クリティカルなタイミングで Unity Editor 自体が死ぬ。


何かエラーを出力してくれるとうれしいんだけど、Unity Editor と被コンパイル対象との間に微妙な齟齬があるようで、

本当にクリティカルなタイミングだと、何のエラーも吐いてくれない。

このへんはそのうち Sub から Main への合流手段が提供されるかもなーと思っている。


ちなみになぜ Main Thread でwsのpushを受けないか、というと、

Mainで受けようとすると Unity Editor それ自体が完全に停止するから。 


Main Thread の流れを阻害してはいけない。ナムアミダブツ。


Sub Thread バンザーイ!!!!



4.Unityからコンパイル時の情報を引き出す

Unity Editor にコンパイル命令を入力できれば、Editorのログファイルにコンパイル状況が書き込まれる。

ログファイルはMacとWinでパスが異なるが、複数プロジェクトがあっても基本一つのファイルをみている。


Mac

Users/Library/Logs/Unity/Editor.log

Windows

Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + ¥Local¥Unity¥Editor¥Editor.log


このファイルを、Editor側で動くtailのようなTimerロジックから読み込み、

読み込んだ結果をwsでエディタに送り込んで、コンパイルエラーなどをエディタに表示させている。


この方法の優れたところは、コンパイル中、更にはゲーム実行時のログをストリーミングしてコード上に反映させることができるため、

リアルタイムにコード上のどの値がどう変わったか、をその発生箇所ごとに記録できること。

動画では、00:45あたりから、Debug.Log(string) 関数に対して、L: という文字列を頭に付与することで、

「該当ログの実行記録をこの行に時系列順に表示する」ということを行っている。

例えばゲーム作りの途中で、挙動が複雑なところがあって、そのコードや通過しているかどうかの判定がしたい場合、

どの順番でどこを通ったか、などが目で見て判定可能になる。



5.Unityからコード補完時の情報を引き出す

コード補完は、Sublime Text から Unity Editor、 Unity Editor から Sublime Text へと、複数の非同期/同期通信を組み合わせて実現している。

具体的なシーケンスの例をあげると、


Something.(ドット) とかが入力された

Somethingが型なのかインスタンスなのかプロパティなのかフィールドなのか解析

・var だったら実際にはどんな型なのか解析

・使用されてるusingとかから補完に現れるべき範囲を限定

・補完候補を出力する


といった事をしている。


図にするとこんな感じ。

スクリーンショット 2014-08-03 23.59.54.png

Sublime Text からのInputに対して、キャッシュがある場合は高速なoutputを返し、

キャッシュがない場合は Unity Editor 側で解析と補完情報を出している。


編集中のコードを相手にするので、ほとんどキャッシュがあるはずが無い感じになる。

さらに、コードが中途半端でも解析できないといけない。


この解析まわりは、NRefactoryをUnity用に大改造することで対応している。

UnityのC♯のバージョンにあわせて改変しまくったものを使用している。


送り込まれてきたコードは、実際にはまだ未保存のはずで、 Sublime Text のバッファ上にしか無くて、

key input のたびにドカッとコード全体を送りつけている。

しかしそこはWebSocket、十分に高速。



で、コードの解析には時間がかかるので、解析は非同期な Thread を作成し、解析が終わったら、補完情報を取得、Sublime Text にPushする。

その補完情報の収集のために、Unityのapp + プロジェクト構造の中から、下記DLLを読み込んでいる。


・/Applications/Unity/Unity.app/Contents/Frameworks/Managed/UnityEngine.dll ・/Applications/Unity/Unity.app/Contents/Frameworks/Mono/lib/mono/unity/mscorlib.dll

Unityのライブラリ一式と、C♯用のライブラリ。

・Project/Library/ScriptAssemblies/Assembly-CSharp.dll

プロジェクトのコンパイル結果が入るDLL。

Editor 部分のコードのほか、コンパイルに巻き込まれたすべてのdllが含まれている。

これらすべてのdllの中から、実際に編集中のコードでusingされている内容を絞り込み、

型を特定して、補完情報を送付している。


ちなみに件数が膨大になった場合、ある程度の流量になるように補完情報を分割して送付する、みたいなことをしている。

これによって Sublime Text 側のUI的なロックは無いようになっている。



6.Unityから引き出した情報をもとに、エディタに働きかける

Sublime Text 側に、入力に応じてエディタの動作を設計できるパイプライン的な設定がなされている。

ぜんぜんUnity関係ないけど、方法の一つとして紹介だけ。


Unity Editor から特定のフォーマットの文字列を送り込むことで、フローから Sublime Text のAPIを実行できる。


内容にはSushiJSONという「JSONを書いたらフローが決定される」自作のDSLを使っている。

SushiJSON

https://github.com/sassembla/SushiJSON



たとえば下記のようなパイプライン処理を、Unity Editor 側からセットして実現している。

スクリーンショット 2014-08-04 1.08.03.png


内容によってfilteringして、入力された内容が正規表現にマッチしたら、あらかじめ

記述していたフローに沿ってAPIを発動させる。

さらにその結果出てきたインターフェースに対してアクションをして、何が発生するか、みたいなのも指定できる。

例えばエラーをエディタ上に表示したい場合、

エラーっぽいログが流れてくる

→エラー表示をコード上に出す

→クリックされたらエラーを表示するイベントをセットする


→クリックされたのでエラー内容を表示

→表示された内容がクリックされたら何かするイベントをセットする


→クリックされたら、、、


みたいに、エディタのAPIフローを予約できる。

filteringも多重化できるので、やり放題。

こういうのがいろんなエディタにフロー型の記述方法で入らないかなー。



Unity Editor と Mono Develop への反逆を通じてわかったこと、得たもの

エディタには我慢しない方がいいなーということなど。


派生物がかなり多くなったので、やってみてよかった。

たとえば、

外部プロセス使ってゲームのプレイデータの蓄積とか解析とかを常日頃かけておけると、面白い.


例えば開発中のゲームに対して「どこが遅いかをクラス単位で計測するIL」を仕込んだりとか、

デバッガーさんとかにプレイしてもらって「どこのステージのどの手順で敵が100 -> 10 -> 0になるまでにかかった時間をグラフにする」とか、

ゲーム作りの中で計測すべきあらゆる物事を、事前に計測しておくことができるようになったりする。

まあ通信機構入れて逐一解析DBにぶち込んで解析すれば一緒だと思うけど。


こまかい粒度のことは、コードを書いてるそのときに知りたい。



明日は、Dvorakはしもと さんです!





wrote 2014/08/04 00:00:00

「ブログっぽいものを作るツール」をGoで書き直した


概要

ブログっぽいものをMacのTextEditorで描いて吐き出すツール「publi.sh」っつーのがあったのだが、

ちょっと時間出来てGolangで書き直してみる事にした。


名前は、、、gopublishでいいや。

https://github.com/sassembla/gopublish



オリジナル

こういうテキストエディットの画面から、この記事を作成している。

スクリーンショット 2014-07-22 1.27.56.png


サンプル文章

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean condimentum cursus tincidunt. Proin vitae tincidunt ligula, eu interdum sem. Donec et est egestas ligula feugiat fringilla ut ut tellus. Proin ornare, dui vel porttitor convallis, justo est ultrices ligula, quis venenatis dui metus et risus. Cras at eros vitae ante tincidunt semper. Nunc sollicitudin egestas magna, id aliquam ipsum ultrices nec. Nunc ut dictum dui. Donec ornare ligula consequat, blandit leo eu, vehicula erat. Vivamus vel sem a ipsum porta viverra in quis urna. Nullam egestas odio in arcu faucibus porta ac at est. Maecenas mauris lorem, tristique sed mi sagittis, ultricies ullamcorper nunc. Pellentesque ante leo, malesuada et sem quis, cursus posuere mi. Sed a sapien at massa molestie rutrum.

Ut semper, orci nec ullamcorper rhoncus, elit felis fermentum lectus, vitae dapibus arcu orci vitae tortor. Integer fringilla nunc nec dui pharetra, quis dapibus nisl dignissim. Cras at vulputate urna, vitae volutpat sapien. Vestibulum rutrum lorem vitae erat tincidunt tristique. In ut nisi purus. Praesent aliquet scelerisque volutpat. Integer sodales arcu et adipiscing elementum. Cras quis lacinia nunc, nec molestie erat. Vivamus id massa luctus, condimentum urna non, cursus nulla.

Sed id est magna. Proin feugiat ligula sollicitudin, bibendum justo a, mattis turpis. Quisque quis justo at dui faucibus cursus. Nullam et pulvinar nunc. Donec vitae ligula sit amet diam porta porttitor ac sagittis nisl. Donec ligula est, ultricies eu vehicula nec, egestas placerat purus. Ut ornare, lectus in hendrerit mattis, orci metus vehicula erat, sed laoreet felis nulla in lorem. Nulla suscipit augue quis lectus cursus mollis. Sed malesuada adipiscing elementum. Vestibulum id urna ullamcorper, adipiscing odio vel, consectetur enim. Etiam nisi arcu, volutpat vel venenatis quis, mollis sit amet dui. Mauris vitae magna dignissim, volutpat leo eget, fringilla eros. Nullam nulla magna, elementum vitae mollis non, bibendum vitae tortor. Nulla placerat purus in ligula ullamcorper pulvinar. Cras sed facilisis massa, nec condimentum justo. Interdum et malesuada fames ac ante ipsum primis in faucibus.

Praesent scelerisque ligula dolor, ac hendrerit magna aliquam sed. Aliquam tincidunt pretium dui, et ornare nunc. Aliquam erat volutpat. Donec sit amet gravida tortor. Nullam nec placerat arcu. Mauris tristique nunc aliquam est consectetur, sit amet congue sapien ullamcorper. Nulla sagittis, urna non fringilla malesuada, eros turpis malesuada arcu, ac venenatis diam lectus vel orci. Maecenas laoreet lectus et orci pharetra laoreet. Phasellus vel tristique lacus.

Pellentesque quis feugiat dolor, nec mattis nisl. Sed non purus ac sapien rhoncus mollis. In et orci porta, pretium nibh ut, commodo nulla. Morbi et metus mattis, feugiat quam mollis, pulvinar libero. Mauris accumsan ornare urna eu aliquam. Sed mollis eros fringilla libero hendrerit mollis. In nisi nisl, porta eget sapien non, dictum vestibulum ante. Nam lacus tellus, egestas sed dolor at, convallis scelerisque turpis. Proin nec velit elit. Curabitur a tincidunt risus, vel volutpat nunc. Curabitur et semper orci. Nullam tincidunt, quam blandit lacinia euismod, dolor turpis egestas orci, ut viverra turpis sapien ac mauris. Fusce hendrerit massa nulla, id luctus dolor imperdiet a. Ut at pellentesque turpis. Cras vitae tortor vel ante volutpat faucibus sed at orci.

Generated 5 paragraphs, 511 words, 3416 bytes of Lorem Ipsum

いろんなfontを使ったり

(順にDFPゴシック, Time, Osaka)


リンクとか

http://sassembla.github.com/Public/


下線がひけたりとかする。


斜体にできたりとかnice boat感ある。



ネタ画像

スクリーンショット 2014-05-03 23.30.31.png

サンプル2

画像サンプル2、キモい生き物を中央揃えで

kaiteteturai.png



Codeとか

たとえばXcodeとかで書いたコードはいろいろシンタックスハイライトとかで綺麗に見える訳ですが。

頑張りたくないので書いたのがそのままhtmlにならねーかなーと思うんだわ。

んでそのうえで、強調とかをしたい。


#import "AppDelegate.h"


@implementation AppDelegate


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

{

    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];

    // Override point for customization after application launch.

    self.window.backgroundColor = [UIColor whiteColor];

    [self.window makeKeyAndVisible];

    return YES;

}


ToDoとか

・コードのコピペしたものを、どう囲むか、っていうのが問題。以前は色でなんとかしていたが、

機構による制約がなくて、ルールが産まれてしまっていた。無駄なルールは殺したい。


・デザインについて、せめてヘッダとフッタはつけよう、という話。

誰が描いたかはもっと外側に表示されればいいよねーって話はあったので、まあはい。


・外部画像リンクを描いてどうこう、っていう手順を実現する気が無い。のでやらないで良いと思っている。




wrote 2014/07/20 21:39:32

AllJoynであそぶ


概要

iOSとかAndroidとかを近接通信で結ぶライブラリ。

https://www.alljoyn.org


通信を行う方法として、wifiとかBTとか、それらのなかから何かを使う、Anyとかが指定できる。


ようは、Macとかの旧rendez-vousみたいなことができる。

作ろうか迷ってたら見つけて、動いたので遊んでみてる。

中の人たちはQualcomm。



サマリー的な情報

iOS用、Android用、Unity用とか、コードとかSDKが公開されている。

Unity用にはインストラクションが公開されてる。

公開されてる彼らのgit repoがあり、開発継続されてる模様。

https://git.allseenalliance.org/cgit/core/alljoyn.git/summary

使い方

まとめたら追記する。


自分はiOS と Androidしか試してない。

そのうちWindowsPhoneとかでも動かしたい。




wrote 2014/07/14 20:38:55

Unityのコンパイル中か否かをメインスレッド外から見分ける方法


概要

そもMainThread外からそういうのを知る方法があるのか?

という話をしていたら、


Unityがコンパイル時に作成、削除してるファイルの存在をけーご君から教えて貰った。



内容

Unity Editorがコンパイル中にSublimeSocketAssetのコード補完走らせたりすると、

SublimeSocketAssetが原因でUnity Editorが固まる、という感じだったので、

対処法としてコンパイル中だったら補完を走らせなくする、とかを考えようとしていたが、

MainThread外からUnityがコンパイル中かどうかを知る術が無い。


というわけで、下記の出番。


Project/Library/ScriptAssemblies/CompilationCompleted.txt というファイルが、

・コンパイル開始時に消される

・コンパイル完了時に作成される

という挙動をしてる。

Win版も一緒っぽい。


わかりやすいかどうかはアレだがgifで。


2014-06-30 00_17_06.gif


SublimeSocketAssetだと、ファイル保存のアクションからUnityのコンパイルを(Unityから開いたファイルで無くとも)

実行されるので、


保存(⌘+s) -> コンパイル開始 -> Finderから該当のファイルが消える -> コンパイル終了と同時にファイルが現れる


というのが観測できた。


コンパイル中にUnityEditor内でThread走らせると、変な死に方することが有るらしい。

まあなーーー実行系がそれだしな。

このへんでコンパイル中だったら、みたいな処理を作るかなあ。




wrote 2014/06/29 23:00:04

Suddendeathonした


概要

ぬる舗でのUnityイベント第二弾。

「プレイヤーを即死させる」というのをテーマに、即死ゲームを作るハッカソンをした。

制作者5人、チャレンジャー1人、という構成で、

チャレンジャー枠の人間を殺すためにハッカソンでゲーム作った、という感じ。



釣りっぽいやつと言い張る未完成即死ゲー

未完成すぎるクソゲー枠。

スペースを押すとキャラが画面上部に戻る、って言ってたけど

実際戻らず一直線に落下して死んだ。

正直すまなかった。

スクリーンショット 2014-06-29 23.36.30.png



アイワナをPS3コントローラで動かす2D横スクロールアイワナ的即死ゲー

りんごが襲ってきて殺すゲーム

近寄ると散弾のようになって襲いかかってくる

ringoKill.png

プレイヤー側

無慈悲に死ぬ


見づらいけどトゲが上下になるステージで、プレイヤーが死ぬ。

player.png


Vitaで殺す

Unityちゃんが開幕ゼロ秒で敵にたたき落とされる地獄のような2D横スクロールゲーム

BrNQYxTCEAEni3F.jpg


Vitaでうごくのいいなあ。いいなあ。でも死ぬ。


余談だけど旧型Vita持ってる人に

「知ってます? 新型ってMicroUSBで充電できるんですよ」

って言うとものすごく新鮮な表情が見れるのでオススメ



早押しデスゲーム

Macで、左右の⌘ボタンを使う。

画面に「!!!!!!」が表示された瞬間により速く⌘を押した方が勝つ。

敗者は爆発して死ぬ。


タイミングがランダムだったり、フェイント?があったりして、集中力を強いられ、殺される。

唯一、制作者がチャレンジャーに殺されたゲーム。


決着の瞬間

スクリーンショット 2014-06-29 23.41.15.png

爆発して死ぬ

ayu.png

この間が素晴らしい。 敗者は爆発して死ぬ。



即死後記

終止適当な感じで即死が進められて良かった。

ただこう、環境としてもっといいものにしたいなあと思ったりした。


即死ゲームを作るには時間が幾ら有っても足りない。

より良い即死をつくりだしたいもの。


ピッザうめえ。


6人でM4枚はわりとギリギリだった。


その後大変遅刻するアイドルを待って待って待って待ってベルギービールちょっと飲みにいけた。



次回

8月なかに殺りましょう。


wrote 2014/06/28 12:09:45

製麺所になりたい人生だった


概要

渋谷ぬる舗に製麺機が来ました。

あわせて自分も渋谷ぬる舗に住むことにしました。


製麺します。


wrote 2014/06/25 14:58:21

UnityのAsset、SublimeSocketAssetの更新履歴を公開


概要

メモまでに。

UnityのAssetStoreに、AssetをSubmitしてから、どのような間隔でRejectされたりApprovedされたりしたかの記録。



以下


update 2014/06/20 01:31:47 1.8.0 in review

released 2014/04/07 00:00:00 upされてたあああああ はえええええ!!

updated 2014/04/06 20:13:34 1.7.4 1.7系のラスト投入

released 2014/03/08 7:35:53 up! はええええ

updated 2014/03/05 9:35:27 in review

updated 2014/01/11 18:28:20 ひさびさのアップデート、Sublime3との連携用に、用意する。ver 1.7.0

released 2013/08/12 00:00:00 だったらしい、、、えーーーメールもらってないよ、、

update 2013/08/08 10:00:00

rejected 2013/08/08 07:57:50 メニューの項目、止めない?→アッハイ

selfreject 2013/08/05 09:04:10 バグが有った、特定条件下でのクラス補完がされない。

update 2013/07/29 00:06:02 補完入り

released 2013/07/10 00:00:00 14:32:32 ドキュメントの更新、Win版対応ST3

declined 2013/07/09 08:27:54 なんかreadmeにメアド書けとかそのへん。

released 2013/07/09 08:27:54

update 2013/07/01 00:00:00

released 2013/06/20 13:23:44 名前にUnitySublimeSocketAsset って使ってたら怒られた 規約読めと。

rejected un思い出すable

released 2013/06/04 13:44:12 初up



かかる日数

日数に関してはかなりランダム。だと思う。

最速だと1日で終わったことがある。


問い合わせについて

けっこうな頻度でメールを返してくれる。

ただクッソ忙しいタイミングはあるようで、

以前「どう? どう?」って急かしたらメールで「今マジ忙しいから、今度は10日後に急かせ、な?」ってもらった。



通知について

Approveされたらヤッターって感じでStoreに並ぶんだけど、メールがくるかどうかは担当者のきもち次第らしいので、

プロモーションするなら知りたいよなーと思うけど運次第。


自分は、適当に自分のAssetのページを監視するツールを作った。


できれば自動化してほしいなーーってお願いUnityさん!




wrote 2014/06/20 12:12:37

UnityMQTTを受ける


概要

C♯用のライブラリも増えてきたので、Unity4.5の時点でつかえるものを見繕ってみる。

候補は、

MqttDotNet

https://github.com/stevenlovegrove/MqttDotNet


と、

m2mqtt

https://m2mqtt.codeplex.com


と、

nmqtt

https://github.com/markallanson/nmqtt



AndroidならばJava、iOSならObj-Cのライブラリがそれぞれ有るので、そっち使ってラップしたほうが楽そう。


なんだけど、C#でパァーっとやると実験に使えそうな気がしたので、

今回はnmqttを使って遊んでみた。



wrote 2014/06/14 21:51:29

WSDっていうシーケンス図を文章から作ってくれるサイトがあって便利だ


概要

WebSequenceDiagrams

https://www.websequencediagrams.com

ていう、文字列をシーケンス図にしてくれるサイトがあって便利を感じた。


紹介

みためこんなの。Styleがデフォルトだと何故か「ナプキンに書いたような奴」になってる。

スクリーンショット 2014-05-29 18.42.04.png



A->Bとか書くと図が出来る。

逆にB->Aを書けば図も逆が書かれる。


突然Zとか書いても新しい軸として追加してくれる。位置とかスペースのマージも。


通信:内容 みたいに内容も書ける。日本語もいける。


altもいける。

作った図は画像としてDLできる。


文字から作られるのでコピペが容易。

スクリーンショット 2014-05-29 19.06.39.png


左列にサンプルが有り、押すとひな形がテキストに現れて、グラフ化される。

いろんな種類の通信表記に対応。途中から有料。


間違って書くと、errorを出してくれる。どこがエラーかもでる。


図の方にカーソルを持っていくと、該当行がひかる。という芸コマっぷり。

cursor.pngスクリーンショット 2014-05-29 19.21.19.png


良さ

シーケンス図、要素を追加したりするのが面倒だったり、人によってフォーマット差が激しかったりする。

そのへんを、平易な文字列で記述してなんとかする、っていうのが凄く良い。


あと文字列なので、バージョン管理できる。


良い。

wrote 2014/05/29 19:14:39

やりたくない事から分類したゲームエンジン考


概要

変更可能性にだけ焦点をあててまとめた。


基本的に「やらないですむならやりたくないクソみたいな努力」をするのがいやなので、そのへんの観点で纏めた。


レイヤー分け

ゲームエンジンに対して、次のレイヤーを定義してみる。

下から積み重なっていくもののようなイメージ。


1.基盤性能確保レイヤー

=自由度、性能調整性のあるレイヤー。

ゲームランタイムとしてどの程度の性能を求めるか、っていうのを弄れる。

根っこ。


2.構造化機構レイヤー

=構築力、フォーマット維持性を保持してるレイヤー。

フレームワークとしてどの程度追加構造を構成する能力を求めるか、っていう機能があるところ。


3.ゲームエディタレイヤー

=ゲームエディタとしての性能を保持してるレイヤー。

いかに抽象的にゲームのステップを扱えるか、みたいな機能があるところ。

いろいろなものの隠蔽と、それらをコントロールするデザインが必要。


独断と偏見で既存のエンジン数個をこのレイヤー内に置いてみる

レイヤー 1->

レイヤー1までだけだと、構造化を自分でやらないといけなくて、FWのメンテコストを自分が負うことになってつらい。

コードを書く量がメチャメチャ必然的に存在する。


細かいところまで弄れるので、特化させる足がかりとして有用。


要はScaffoldみたいな位置。


このレイヤー1と2の間、1寄りにいるのがCocosシリーズ。


レイヤー 2->

レイヤー2まで備えてると、コードが走るランタイムは隠蔽されている。

書く場所はプラガブルに用意されており、依然としてコードを書く量がかなり必然的に存在する。

が、構造化に対するフォーマットは持っている。のと、そのへんのメンテもゲームエンジン側が負ってくれる。


ゲームエンジンのコード自体は隠蔽されており、変更が不可能な反面、

エンジン自体の制約を守ればアップデートでもクソ面倒くさいことにはなりにくいと思う。


このへんを超えて、次のレイヤー3のちょい手前にいるのがUnity。 



レイヤー 3->

ゲームエディタの域。3までエディタの域を押し進めてくと、いろいろ隠蔽した上でコントロールすることが可能になる。

もちろん2も内包してるので、コード書いてなにやらも可能。


GUI天国。一覧性がコードだらけにくらべたらかなり良いと思う。


このへんにUnrealEngine。



振り分けてみた感想

根っこまで弄れるっていうのは、根っこまで変更した場合、そのメンテコストを負うってことなので、

面倒くさくなるしゲームエンジン自体の更新に際して非互換生むので俺はパス。


ゲームを作って遊ぶ事に専念したい。基礎のメンテナンスに関わりたくない。


コンパイルのある、バイナリになる言語でアプリケーションの背骨が作ってあって、

その他の言語でその上に肉付けができる、っていうのが、区分けが安定するしエンジンのメンテコストを背骨のほうに封印できるので楽。




こちらからは以上です。

wrote 2014/05/28 14:14:37

プログラムを書くためにやってること


概要

流行ってるので。

http://cside.hatenablog.com/entry/2014/05/19/021253

http://qiita.com/voluntas/items/f8eceda58f1bdfd33905


といいつつ俺のはポエムです。



記憶しなければいけないことを減らす

忘れてもいいように、情報は「それが必要になる箇所にできるだけ残す」ことにしてる。


情報とその情報が必要な物事の間に距離とか時差とかがあると、その間が原因で情報が無駄になる。


減らす効能として、次がある。

・覚えておくべき事が少なくできる = 無駄な努力の削減ができる

・一度に複数のことに関わっても何してたか思い出すロスが減る(そもそも覚えてない確信がある



ルールを作って毎回悩んでいる物事を減らす

たとえばメモを残すときに、タイトルについて悩む事は無いだろうか。


自分はあって、毎回あって、面倒くさくなったので、一貫性と時事性を求めて、 2014/05/20 22:59:11 とかタイムスタンプを使う。

ショートカットにしておくと楽。


毎回悩む事を減らすと、その悩みが永遠に消える。


また、メモのフォーマットを決めたりすると、これまた悩み事が減る。

覚えてられなければ覚えてられる範囲のルールを策定すれば良い。



100%誰かの為のものは作らない

最低でも自分のために%が割り当てられるものを作る。


誰かのため、だと、自分がその誰かのニーズを見誤っている場合、即ゴミが完成する。

完成してもゴミ。ツラい。


また、最低でも自分がニーズの一翼を持った方が、「ああ、このニーズとこの労働は割にあわないな」とかなって、諦められて良い。


価値を生まないものを作り上げることに価値はない。

作って使って利益を得る事に価値がある。


自己満足ならそれはそれで。



習慣を作る

作れる。試して長続きすればそれはもう習慣。

長続きしなかったらアレンジして試す。



自分のケツを蹴る方法を習慣にする

例えばタイマーをセットして時間に追われるごっこしたり、

images.jpeg


何でも良いけど、自分を急がせる手法を用意しておくと捗る。

捗らなくても手が打てる。



自動的に禁止する

自動化の最も良いところは、何度自分がルール違反をしても、飽きる事無く注意してくれるところ。

人だと飽きちゃう。あきれ(られ)てしまう。


また、ルールは自動的に守れるようにしておくと楽。



選択肢を増やす

今までやってない事を試し、選択肢を増やす。

一辺倒になると硬化/老化してヤバい。


トンカチを持ったら全てが釘に見える、みたいなのを避けるには、工具をいっぱい用意すれば良いと思う。

今まで単なる釘に見えてたものが、何かを知った事で違った見え方になることを期待する。



そうやって増やした選択肢の結果で、

全然関係ない物事が考え方に影響を与えたり、人と会わせてくれたりする。


コードを書く時には、選択肢を多く持っておく事は、文脈を実現する手段として使える。これは例えば次の話。



いろんな疎結合をデザインに利用する

いろんな疎結合を組み合わせることで、意図を表象したりできる。

例えばなんらかのアプリケーションを作ったとき、


コード外とコード内にはそれぞれ別の種類の疎結合が有り得ると思う。

コード外の世界が持つ疎結合の特性と、コード内の世界が持つ疎結合の特性は大きく異なる。


コード外での疎結合というと、

ありもののプロトコルで繋ぐとか、ファイルで読むとか、プロセスを繋ぐとか。

一般性が高く、なんらかの方法で結合の手段の明示が必要なものら。


コード外での構成に使える手段はめっちゃ多いが、多用しすぎると誰にも解らないパーツ群になってしまう。

主に明示性、凝集性、あとで見てワンセットに見えるかどうか、Purgableに見えるかどうか。

(これらを結びつけられるのはドキュメントだけだ。ドキュメントの「まとめる力」がどれだけ強いか、知ってる人は無茶はしないと思いたい。)



コード内では、疎結合の手法とバリエーションによって「パーツ単位」や「考え方」の単位を、あとからコードとかAPI見た人に、より強くアピールする事が出来る。

手段を明示的に使い分けることで、コードに文脈を与えられる。

特に手段が多い言語とかで楽。

ただし、パターンに見せるためには、パターンに見せられるだけのプレゼンテーションが必要。

4種類の柄を使って着物デザインしました、って言っても、相手に近過ぎたら1種類にしか見せられない。

どうやって一歩ひかせて俯瞰させるか、みたいなのもデザイン。


部分あるいは全体で捨てられるようにする

疎結合性はこのための条件。

固執するのは良くない。いろいろ試して、「あ、こっちのほうがいいや、これもういらねーや」ってなったら捨てようと思ってる。


疎結合での切り口がうまくマッチすれば、もしかしたら再利用できるかもしれない。


捨てられないものは腐る。ゴミは捨てれば良い。



身軽さを保つ

環境を移動するときに、毎回持ち歩かなければいけない重い荷物が多かったりしない?


それって結構邪魔じゃない? みたいな思考で、


・頻繁に使わないツールは入れない

・使わなくなったツールは捨てる

・デフォルトで使って動作が良いツールを使う


などを守ると、あとはDropboxの2GBに入るだけの質量のデータと、Githubとかが有ればOKなのでは。


もっといい制約を探す

最高の制約は、最高のゲームになる。

懲りずに改良するとしたら、制約の部分が良いと思う。




wrote 2014/05/20 22:55:22

ぬる舗 Unity Hackathon #1 やった


概要

ぬる舗@渋谷でUnityのハッカソンやった。


特に指向性のあるハッカソンではなく、とりあえず触ってみたいっていう人とか

作りかけのプロダクトがある人とかがモクモクしてた感じ。

Pasted Graphic 4.tiff

今後も隔月で適当にやろうかと思う。


場所として、渋谷近辺で平日夜とか休日に8人くらいまでなら使える感じなので、

やりたい事とか有る人は俺まで是非。



開始

12:00くらいからぽつぽつ集まり出す。


ずーっと自分がC♯4で書かれたプログラムのC♯3.5(Unity)移植についての愚痴を聞かされていたメンツがいた。



途中、椅子を作ってもらう

途中からすわる椅子が足りなくなる予定だったし実際そうなったので作ってもらった。

ちなみにまだまだある。

Pasted Graphic 3.tiff



メシ1

中華屋。

別に遠近法はおかしくない筈。

Pasted Graphic.tiff



感想

Unityちゃんが産まれたことで、まず作ってみよう、で作られるものがとてもとてもとても華やかになった。

平和と愛が感じられる。

配管工のおじさんは、もう、居ない。

Pasted Graphic 1.tiff



メシ2

良いメシテロ素材が手に入った。

あと、人類のために、この世にはピザの枚数を計算する機構が必要な気がする。

Pasted Graphic 2.tiff



次回予告

Sudden Death Jam

http://chouseisan.com/schedule/List?h=b56b7e20aa216f708b76fdb653a96f95




wrote 2014/05/11 16:26:18

ngrokで遊んでみる


概要

そのへんのマシンのNAT越えして、サーバとして扱える、

中継ポイントを提供するサービス + サーバ側で動作するアプリケーション。

https://ngrok.com

デモとかに使える感高い。

nginx立ち上げてHTTPサーバとか簡単に動いた。


nginxでWebSocketへのプロキシを行ってみたところ、課金しないと無理っぽかった。


HTTPサーブしてリクエストとか

ngrokを立ち上げてるTerminalから、httpリクエストとかがみえる。

スクリーンショット 2014-05-03 12.36.43.png

http://localhost:4040/http/in

で、詳細なアクセス情報とかが出る。スクリーンショット 2014-05-03 13.15.57.png



HTTP以外のリクエストも可能、そう、signupすればね!

プロトコル指定してフォワーディングできるんだけど、

ngrok -proto=tcp 22


Server failed to allocate tunnel: Non http-protocols are only available after you signup at https://ngrok.com/signup


サインアップを求められる。

月間2ドル、年間で25ドル。

https://ngrok.com/pay



という感じだった。で、もうちょい調べてみようかなーと思い。


FAQによると、

https://ngrok.com/faq


Q.ngrokってWebSocketのトンネルってできるの?

A.できるけど、特にサポートしてないよ。

どっちやねん。



この状態のままで、nginxを立ててHTTPコンテンツ配信→ブラウザからのWebSocket接続、 を試してみたところ、

WebSocket接続が拒否される。

スクリーンショット 2014-05-03 14.04.50.png


手元のnginxまできてない。というわけで、誰か課金して試せばいいのではないか。


試して失敗してる人を見つけた→

http://stackoverflow.com/questions/22830330/how-to-forward-a-websocket-server-in-localhost-with-ngrok



wrote 2014/05/02 23:21:31

🍣


概要および全容

🍣が降り注ぎます。


ruby -e 'C=`stty size`.scan(/\d+/)[1].to_i;S="🍣";a={};puts "";loop{a[rand(C)]=0;a.each{|x,o|;a[x]+=1;print "[#{o};#{x}H [#{a[x]};#{x}H#{S} "};$stdout.flush;sleep 0.01}'



こちらの方の素晴らしい作品のパクリです。

http://deeeet.com/writing/2014/04/30/beer-on-terminal/



疑似

sushi.gif

wrote 2014/04/30 22:12:45

ムービーは無理だけどgifだったらGithubにもアップできるよな的な理想を追う


概要

去年くらいにいっとき盛り上がったような話で、

yidevでの @sonson_twit さんのお話によって自分にとってベストな解がみつかった感じがするので纏める。


githubには動画ファイルはアップできない。まあ重いし帯域が云々だし。

なので、ムービーからgif画像を切り出してなんとかする、ということが広く行われているよねーんでこのツールいいよ、という話。


結論だけ言うと、これがとても自分の欲しかった内容にマッチした。


gifbrew

https://itunes.apple.com/us/app/gif-brewery/id435989461?mt=12


こういうのができた。

2014-04-26 20_21_04.gif


まず基準として、自分の理想のツール条件と理想のフローを列挙する。



俺が使うツールが満たすべき理想条件の列挙


1.デフォルトについて

・デフォルト設定で使える


☆☆☆ ツラいツールかどうかの壁 ☆☆☆

・デフォルト設定への改変が少なくても済むものを使う

・デフォルト設定への改変が自動化できる


☆☆☆ クソツールの壁 ☆☆☆

・デフォルト設定がクソ

・デフォルト設定への改変が自動化できない



2.環境について

・プリインストールされているものが使える

☆☆☆ ガマンの壁 ☆☆☆

・インストールが楽なものを使う

☆☆☆ クソ環境かどうかの壁 ☆☆☆

・インストールがつらい

・バグが多い

環境については、対症療法が多い環境は逃げろ。とめっちゃ思う。無駄な努力だ。

おそらくその環境でやるべき事ではないんだろう。。。



今回の理想のフロー

1.デスクトップのなにやらを撮影する -> 

2.撮影データをgif化する -> 

3.字幕をつける -> 

4.アップ、パブリッシュする


これらの行程に使うツールがすべて疎結合だと理想的。


具体的にはファイルIOが独立してると良い。



打線を組んでみると

1の動画を撮るのに対しては、Macにはウィンドウ単位でmov撮影ができるQuickTimeが入っているので、すべての条件を自動的にクリアできる。


2、 3 が問題で、



2、gif化は漠然と「やりたいけどなーーうーーんモチベ沸かねー」という状態だった。

Webツールがあるのは見てて、記録はしてたけど、なんか手が動かなかった。

なので、VimeoにアップしたembedなURLとかを持ってきてごまかしていた。


そこに今回 光が!!



3、字幕に関しては、以前は字幕に対してiMovieを使って「これは人類が触るには早すぎるのでは、、」と思うとかしてた。 Amaraを見つけたことであっちょっといいかなーっていうかUIはこういうのでいいよなーとか思っていたが、

結局登録メール届かないので無かった事にした。 

あとブラウザバック誤爆して死ぬ環境は地獄だと思う。unbackableほしい。そしてそれはWebではない、Appだ、、

そこにも今回 光が!!



4、pub場所に関しては成果物の形態によりけりで、movファイルであればVimeo、という感じ。gifだったらgithubとか、Dropboxとか。

YoutubeはGoogle+連携求めてくるしどうでもいいメール一杯送ってくるので無い。


gifbrew

「既に存在する動画ファイルをgifにする」ツール。

https://itunes.apple.com/us/app/gif-brewery/id435989461?mt=12


500円する。 だがそれ以上の価値がある。


スクリーンショット 2014-04-26 17.58.41.png

QuickTimeが吐いたmovファイルに対して処理ができる。

処理の幅が広く、

・crop + resize

・キャプションセット

・編集ファイルを吐く(.gifbrew

・出力されるgifのフレームレート、色情報設定が詳細に可能(弄らず動いたらもっと嬉しかったがアプリ単位で覚えるので許容範囲

・音!?


こういう編集画面

スクリーンショット 2014-04-26 17.57.40.png

追加で、同じUI上でキャプション付けられたりした。 便利ー。

スクリーンショット 2014-04-26 20.27.02.png


どうでもいいけど最近帰宅→夜勤→深夜帰宅しては、

テレビ競争の捕食者が居ないタイミングな深夜4時くらいにHuluでガッチャマンクラウズみてる。1年前を生きてる。


gifファイルへのセッティングも簡単にできるが、できるだけデフォルトでやりたいところ。

スクリーンショット 2014-04-26 20.26.25.png


また、gif化条件で全フレームをpngでアウトプットができるモードもあり、デスクトップがやられた。

スクリーンショット 2014-04-26 20.33.06.png



こういうのも教えてもらった


Licecap

http://www.cockos.com/licecap/


窓枠が出て、特定の範囲を撮影しつつgifファイルにする。

スクリーンショット 2014-04-26 17.48.38.png

撮影しつつそのままgifというのがミソで、手軽。


謝辞

ツールを知るきっかけをいただいた @sonson_twit さん、@masanobuimai さん、 @イケメン

ありがとう。

 

wrote 2014/04/26 18:57:57

yidev参加者のつもりで行ったらまさかの登録してないのに来た人だった話


概要

yidev

http://atnd.org/events/49477


に参加しているつもりで行ったらまさかの登録すらしてないのに来た人だった。

カスだなーぁぁ。


到着して着席して「そういえば矢張り申し込んだ覚えが無い」と思い立ってatndみたらやっぱ申し込んでなかった。

本当にすいませんでした。


幸い空席があったので、その場で申し込んだ。



LLDB + chisel = ∞ 

by @dealforest さん

https://speakerdeck.com/dealforest/lldb-plus-chisel-equals


LLDBと、それを簡単に使うための整理されたツールであるFacebook chisel のお話だった。

Facebook chisel

https://github.com/facebook/chisel


値の書き換え、表示領域の図示に始まって、

実働している環境にズブズブ入れるんですよ、そう、LLDBならね、というお話だった。


~するのは面倒くさい、という精神がとてもステキです。

頑張りたくない。


やっぱりデフォルトが充実してる環境は良いっすねえ。無駄な努力を排除できるし、環境再現性もあるし。

UnityでもiOS上でこのレベルの浸食と書き換えを実装したい。


CoreTextな話

by http://@sonson_twit さん


死霊URLがわかんない。


CoreText拡張のお話とか、無限にツールチップが出てくる階層ビューの話がとても面白かった。


拡張した結果のインターフェースの見え方に汚さ、醜さがなくて、素晴らしいなーと思った。

さーっと作ると「動くんだけど見た目が汚い、醜い、無様、無作法」という感じになりがちなので、

中身は(コードがどうかは知らないが表示結果を出すロジックとして)とても丁寧なことになってるんじゃないかなーと勝手に思っている。


「オープンソースにする前提のほうが綺麗に書ける」

という話もあり、確かになーと思うなど。


謎の情熱で熱量が高い方みてるとウズウズする。

もっと遊ぼう。


最後に紹介されていた、Githubに動画で紹介上げられないよねgifにするには、みたいな話が個人的に最大の収穫だった。

別項に譲る。




wrote 2014/04/26 17:52:50

Vagrant+VirtualBoxでMac中にUnityビルド用のMac環境をマルチに作る


概要

Vagrant側で同じMac VMを立ち上げまくっておけば、iOS/Androidとかが同時にビルドできる。


Dockerが流行ってきてる今、Platformから逃げられないの時代遅れだと思いますがまあはい。

Unityを複数立ち上げてるとろくな目に合わないしJenkinsからの制御とかが面倒くさいので、

自動化を容易にするためにやってみる。

MacはもともとMac内VMを2台まで立ち上げられるライセンスなこともあるし、

MacをホストにゲストにMac x 2 を用意して、

同一Unityプロジェクトの複数環境同時ビルドを可能にする。


最終的に、ビルド開始 ~ 完了時までを、Vagrantから起動してるMacインスタンスで行う。

Xcodeの設定とかも一つのMacインスタンスでどうにかできるので、ラク。



VirtualBoxにMacを入れる

以下が参考になる。

[Vagrant & VirtualBox] VirtualBox: guest OS に OS X Mavericks (10.9) をインストールする

http://www.d-wood.com/blog/2014/03/24_5880.html


Mac VMをまず1つだけ作る。この時点で2つ作る必要は無い。boxを作る際の原型にあたる。


このときのVirtualBox名はVM_NAME

内部にインストールするMac OSのユーザー名はVM_INTERNAL_USERNAME とする。


App Store からMavericksをDL

特に何の注意点も無い。


iesdのインストール

gem install iesd


ルートじゃない場合、権限系の調整は必要。


dmgを作る

iesdを使ってMavericksのdmgを作る。特に何の注意点も無い。


dmgをVirtualBoxに食わせる

ここではまった。

メモリを4gbにしたらインストーラ自体が起動しなかった。

デフォルトサイズの2gbで作って後で変更とかかな。


Mac向けの各種設定を行う

いろいろ落としてProvisioningとかCertificateとか。

Xcodeの設定とか、Unityの設定とか。Androidの環境セットとか。

大変面倒くさいが一回で済む。



VirtualBox内のMacにVagrantからの通信を想定して設定を行う

あとでVagrantからsshで入るので、port番号を2222番(vagrantがデフォルトでセットするport forwarding 設定)を作る。

VMマネージャ > 設定 > ポートフォワーディング

スクリーンショット 2014-04-27 1.29.06.png


ホストの2222番ポートをゲストの22番ポートに繋ぐ。

スクリーンショット 2014-04-27 1.28.58.png


最後にsshログインを可能にする。

ホストマシンから、pubキーをゲストに入れて、sshで入れればOK。

ssh VM_INTERNAL_USERNAME@localhost -p 2222


ここまでで、Mac VMの用意は完了。

Vagrantで使用する用の準備に入る。



Vagrantをインストール

http://www.vagrantup.com/downloads.html


以上



VirtualBox上のMacVMをVagrant用にパッケージングする

以下が参考になる

Creating a new Vagrant base box from an existing VM

http://abhishek-tiwari.com/hacking/creating-a-new-vagrant-base-box-from-an-existing-vm


vagrant package --base VM_NAME --output ~/Desktop/Boxies/OUTPUT.box

VagrantからMacインスタンスを起動

起動後、sshでの接続を行うために、Vagrantが繋ぎに行く設定をセットしないといけない。

VagrantFile ファイルを作る

vagrant init ~/Desktop/Boxies/OUTPUT.box



VagrantFile に以下を追加

config.ssh.username = "VM_INTERNAL_USERNAME"

config.ssh.private_key_path = "PATH_OF_SSH_PRIVATE_KEY"



起動

vagrant up


で、無事sshで接続されて完了することを確かめられると思う。



ここまでで、VagrantからMac VMが使えて、sshで接続できる環境は完成。

Unityのビルド、Xcodeでのプロジェクトコンパイル、その後のflightとかを行うのは、VM側になる。

Unityのシングルプロジェクト問題、Xcodeのビルド環境問題、Androidのビルド環境問題を解決できる感じ。




ビルド後のパッケージのアップロードとかは、そのままVM側で行う処理にしちゃった方が良いと思う。




以上。

wrote 2014/04/26 16/39/23

Typetalk Hackでチャットからコードハイライトするやつを作った話


概要

コレに参加。


Typetalk Hack Tokyo

http://www.zusaar.com/event/4757003


Typetalk上の書き込みから、

Sublime Text上のコードをハイライトしたり開かせたりするやつを作った。


TypeHighlight

https://github.com/sassembla/TypeHighlight


Typetalkからいろいろ引っこ抜いてくる部分をCredentialごとガッと削ってupしてある。



中身

1.SublimeSocketプラグイン入りのSublime Textを開く

2.今回作ったhtmlをブラウザ(Safari, Chrome, 他)で開く


すると、ブラウザがTypetalkの特定の部屋へのポーリングを適当に開始して、


特定フォーマットの書き込みがあったら、Sublime Text上でハイライトされる。


たとえばTypetalk上で

sam.png


とか書くと、

Sublime Text 上の該当の名前のファイルの該当行が点灯する。

スクリーンショット 2014-04-24 8.40.32.png

クリックすると、メッセージが出る。

1__#$!@%!#__スクリーンショット 2014-04-24 8.40.32.png

もし、該当のファイルがまだ開いていなかったら、

別ファイル上からopenさせるポップアップを表示できる。

スクリーンショット 2014-04-24 8.40.11.png

強制Openとかも可能だけどやってない。

会場のwifiに頼らなかったので、128kb/s環境下での初のハッカソンだった。

完遂できてよかった、



感想

hack(HHVM)でのTypetalkクライアントあり、

by @yone098 さん

Docker本が出る、とのことで、

これか!

https://gihyo.jp/dp/ebook/2014/978-4-7741-6504-2


SmalltalkでのTypetalkクライアントあり、


Typetalk4sあり、

https://github.com/daiksy/typetalk4s

、、おっといけねこっちじゃなかったテヘヘー こっちこっち(嫌がらせ

https://github.com/seratch/typetalk-hack-app

by @seratch_ja さん


Typetalk4s.orgあり、

http://typetalk4j.org

by @yusuke


なんなんだこの濃さは、、!! 

なぜXXXX(意外性のある言語の名前を入れてね!)でそんなことを、、!


ハック時間 1時間くらいだよ? なんて変態密度なんだ。

そう思うハッカソンだった。



ステマとブーメラン

Typetalk最高!! Streaming APIガンバッてください!!



wrote 2014/04/24 1:14:19

SublimeTextでTypeScript1.0をコンパイル+エラー表示 updateしたよ その2


概要

続編 of 

「SublimeTextでTypeScript1.0をコンパイル+エラー表示 updateしたよ」

http://sassembla.github.io/Public/2014:04:11%2017-20-16/2014:04:11%2017-20-16.html


コンパイル部分が適当だったので調整したのと、

コンパイル範囲をRecursiveに拡大した。


おまけで、「いま開いてないファイルでエラーが出てる場合通知」機能もつけた。




保存するとRecursiveにコンパイルする機構



エラー箇所が開いてなければリスト表示→開ける機構

wrote 2014/04/22 1:02:34

Mac OS 10.9向けにnginxとJenkinsセットするなど


概要

10.9向けにやったことないなーアップデートしたやつはそのまま動くし平気だろー

とか思っていたら駄目だったのでまとめまで。



Jenkins

過去の自分の記事を参考に

http://sassembla.github.io/Public/2013:05:13%2016-23-21/2013:05:13%2016-23-21.html

JenkinsのサイトのPackageから入れると、userとかgroupを設定し直した段階で、launchctl loadしても

立ち上がらなくなる。


どこでエラーでてるんだろうなーと悩んだが、Launch系の権限の持たせ方とかが変更になってたのだな。

loadするところでは何も言われなくても、実際にはJenkinsが起動できていない状態になっていた。


で、LaunchAgentsっていうのがあるのかーと探してたら、下記を見つけた。


Jenkins をOS X のログインユーザー権限のデーモンで自動起動しておく設定

https://gist.github.com/shunirr/3522219


デフォルト教信者としては、Jenkinsの.app Packageが仕事しなくなっててつらたん。

だが動いた。


ありがとうございます。



nginx

confの編集、Jenkinsへのルーティングをやって完了。

このへんはとくにかわりなく。

1.4.x系だーわーい。


Macに1.4系入れるのは初めて。


wrote 2014/04/21 18:10:25

アップロード済みの動画に対して字幕を付けるAmara


概要

iMovieで字幕を付けるとか一種の拷問で、フリーでも有償でもろくなソフトウェアが無いなーと思っていた昨今。

あった。

あったよ、いい字幕くっつけるサービス!!


http://www.amara.org/ja/


教えてくれたFredに感謝を。

っていうかググれよって話なんだけどねーーよこんなのググる言葉。



注意:

バグの項に目を通せ。



何が素晴らしいのか

以下の点で素晴らしかった。


・いろいろな言語(Eng, 日, Jawanese, etc..)に対応

・アップロード済みの動画に対して字幕をセットできる

・編集インターフェースが良い

・字幕のみの編集、ダウンロード、アップロードが可能


素晴らしい。



いろいろな言語(Eng,日,etc..)に対応

クラウドソーシングというか、人力でいろんな言語の字幕がひとつの動画に付くことを想定している模様。

よって、見る側が言語トラックを選べる。これは楽だなーーーうん。detailとoutboundに別けた説明とかも出来そうだ。



アップロード済みの動画に対して字幕をセットできる

YouTube、Vimeo、とか、その他のサービスにアップされている動画を指定できる。

スクリーンショット 2014-04-13 16.50.06.png

まゆつばーーー



編集インターフェースが良い

こんな感じ。

Pasted Graphic.tiff

真ん中が字幕を書くところ。

Typeと書いてあるから上のムービー上にもTypeと表示されている。

一つのハコごとに一画面に表示される字幕に対応している。

Space + Enterで自由な位置で改行が可能。

センタリングはオートでされる。


右側が、シーケンス的に字幕の完成までをコントロールするところ。

・真ん中で全ての画面用の字幕を書く

・ムービーのどこからどこまでその字幕を置くか配置する

・complete

という順で作業する。



字幕のみの編集、ダウンロード、アップロードが可能

下記のようなフォーマットで吐かれる。

1

00:00:00,000 --> 00:00:04,000

あっはっはっはっはっは


2

00:00:07,486 --> 00:00:11,906

アッハッハッハッハッハッハッハ


3

00:00:11,906 --> 00:00:15,759

ハッハッハッハ



読み込みをおこなってみたところ、タグ<>が含まれる形で読んでしまうというミスっぽい挙動を見つけたので、

そのへんを後でまとめて通知するつもり。



バグ


届かない登録メール

Twitterアカウントでsign inしたら、「登録メール送ったから確認してね!」って言われたけど、

そのメールどこに行ってるんだ。どこにも届かないぞ。


んでそのあと、sign upから新規アカウントとしてメアド入れたけど

やっぱり届かないぞ。


なんかあかん感じする。


形式読み込みバグ

DLしたSubtitlesを再度upしようとすると、各項目の文字に<タグ>が含まれるようになる。

なんか単純なバグっぽさを感じる。

それでも、タイミングとかが維持されてるっぽいので、まあ


Webサイトの上で何かを編集し続けるとロクな事が無い、という

大宇宙の法則に従うために、こまめにDLしたほうが良いんだと思う。



完成後のEmbededリンクでエラー

embededリンクを吐き出す機構があるが、aws上に置いてあるファイルがおかしいとかで、動かない。

なる、、ほど、、、無駄な時間を、、、



結論

とてもいいかんじなんだがメッチャ壊れている気がする。

WindowsでIEからやってみるか、、、

Oculusのサイトで学んだ事として、IEだと違った画面が開くんじゃないかという

疑いを強く持つ体質になった。



学び

まずスモークテストしよう。

wrote 2014/04/13 15/29/46

Xamarinのバグ/仕様で納得いかないところ


概要

バグというか仕様かもしれないが、ヒデェ感じの感想を抱いたので書いておく。


Mac OS X 10.9.2


XamarinStudio 

Version 4.0.10 (build 5)

Installation UUID: 0997a671-e5bb-4a9d-a520-cb71ff98b7bc

Runtime:

Mono 3.2.0 ((no/7c7fcc7)

GTK 2.24.20

GTK# (2.12.0.0)

Package version: 302000000



別エディタでファイルを編集すると、該当のファイルをXamarinで開いて保存するまでコンパイルに巻き込まれない

再現方法:

Xamarinでコンパイル可能なソリューションを開く

ビルドする

ソリューション内の、Xamarinで開いていないファイルを、別エディタで編集する

たとえ別エディタの編集内容にコンパイルエラーがあっても、Xamarinから開いていなければ、変更前の内容のまま平然とコンパイルできる。

Xamarinで対象のファイルを開き、かつ保存アクションを行ったあとのみ、

正確にコンパイルに変更後のコードとして巻き込まれる。


つまりそこまでしないとファイルを読み込み直さないって事だね。。

このエディタだけで編集する訳じゃないんだから、ビルド時くらい実ファイルから読もうよ、、

というか実ファイルをキャッシュとして持つのは一体なぜなんだ。


Xamarinを再起動しても残ってたんだけど、何故。



ステップイン/ステップオーバー実行できないのにステップインボタンがある

再現方法:

ステップインとか使う。


これは多分仕様なんだと思うが。

ステップインやステップオーバーは効かないか、不思議なジャンプをすることが多い。

1,2,3,5,4,,みたいな。特にメソッドで複数行にわたって引数を書いてるまわりの挙動が怪しい。


コレはキツいな、、と思った。



BreakPointが効かず貫通される

再現方法:

BreakPointを2つ、10行間隔でセットする。

後方のBreakPointでのみ停止する。

間にifやyieldなどは無い。っていうかあっても、後方のものだけが引っかかるのはおかしい。


うーんロックだと思う。

対象のコードがいけないのかな、、



レイアウト設定をリセットする方法が不思議

IDEとして多機能をバンドルしてあるので、

ウインドウの位置が気に喰わずIDE内でいろいろ移動項目をするが、

一通り落ち着いてから「アアーー無駄なカスタマイズだったなー」ってなって

ウィンドウ位置とかを一括でリセットしたい時、リセットボタンを探したんだけど無くて、

かわりにこういう答えをもらった。


http://forums.xamarin.com/discussion/6568/how-to-reset-xamarin-studio-to-defaults

→近所の設定ファイルを消せば良いよ


なるほど! うーーーーーんん!!!!



結論

C♯で.slnがある場合はVisualStudio使おうと強く思った吉宗であった。

wrote 2014/04/12 23:15:10

SublimeTextでTypeScript1.0をコンパイル+エラー表示 updateしたよ


概要

Sublime Text でTypeScriptをコンパイルしたりエラー表示したりする機構を更新した。

screenshot.png


保存(⌘ + s)すると、コンパイル処理を走らせて、エラーがあればコード上に表示する。


サンプルプロジェクト付きの一式はこちら。

https://github.com/sassembla/SublimeSocket3/tree/master/tool/nodeTailSocket/TypeScript



SublimeSocketとは

Sublime Text のAPIを外部から呼べる機構。


事前にFilterを喰わせることで、どんなときにどんなAPIが呼べるか、といった動作を規定できる。

こんなの

https://raw.githubusercontent.com/sassembla/SublimeSocket3/master/samples/rubySample/rubyFilter.txt


DSLとしてSushiJSON

https://github.com/sassembla/SushiJSON

を使っている。


NodeTailSocketとは

SublimeSocketに対してWebSocket Client として接続できるnodeのコード。

特定のファイルをtailして、その内容をwsに乗せて送りつけられる。


SublimeSocketのtoolに入ってる。



以上。

wrote 2014/04/11 17:20:16

CompilableWebという戯れ言


概要

戯れ言です。

UnityがWebPlayerプラグインを捨てるのでハイになって書きました。


UnityがWebPlayerプラグイン無しでもブラウザで動くようになる話はこのへん

http://sassembla.github.io/Public/2014:04:08%2013-36-09/2014:04:08%2013-36-09.html



ホント面倒でやめたい事

「HTMLからいろいろロードしてJSからいろいろロードしてページ単位とかcacheとかコントロールしてCSSロードして画像がリソースが」


かったるいわ!!! やりたいことはビュー描画とローディングとアクションなんだよ!! みたいな話に対して、


コンパイルしたらいい感じに動く、というもののほうが、楽さがあっていいなーと思っている。

で、そこにいろんなゲームエンジンとかがこう、差し込んできた感があり。



これまでのAltJSがもたらしてきたものがとうとうイイ感じになる

これまでのAltJSで自分が一番不満だったのは、Viewへのサポート、

もっというと


HTMLがサポートしている領域でないとブラウザ描画してくれないのですがそのへんにどうアプローチするか


みたいな話で、まあそりゃそうなんだけど、AltJSでビューを持とうとしたやつはGなんとかくらいしか覚えがない。

そして、これからもAltJSではブラウザビューが救える予定はないんだろうなーという気になっている。


AltJSでブラウザでのインターフェース作成が救われたかどうか

そんで、えっと、描画? が、AltJSで楽になった? みたいな話。


Noでしょ。

HTMLを吐き出すコードはAltJSから吐けるようになるから、そこから先は楽に、、みたいな感じで。

構造化できるのはJSまでで、それでももちろんものすごくメリットがあった。


ただ、どこかから先は、HTML、CSS、そのへんに頼らないと表現できない。

そういうカベに当たる。

だって今のブラウザ、HTMLが基礎なんだぜ。

Hyper Text Markup Language なんだぜ。アクティブなGUIの基礎としてはあまりにあまりだ。

→だもんでHTML5ですよみたいな話だったりするし、そうでなかったりもするし。


で、JSだけでこれらHTMLから始まるブラウザインターフェースの全部を御すのは、並大抵のめんどくささじゃないと思っている。

リソース管理やインターフェース階層構造の所持、管理、イベントのハンドリングとか諸々、を、AltJSとウデ一本で、、


面倒くさい。

実際面倒くさい。


そこに、ゲームエンジン、という、画面全部をゼロから作るのをハナから前提にした差し込みが入ったのが今。



描画が可能になる。

階層化が可能になる。

2Dリソースの管理が可能になる。

3Dリソースの多大な表現能力がぶん回せる。

サウンドの力に頼る事が出来る。

コンパイルが可能になる。


しかもゲームエンジン、ゲームがつくれる。


やっと「必要とあらばブラウザインターフェースのルールをコンテンツが作れる」世界になるのかなーと思っている。



これからの、HTML的にお行儀の良いWebデザインと、HTML的にはお行儀の悪いWebデザインと、壊滅的な混沌を運んでくるヤツ

こないだのキョン君のLT大会@tokyoでモン様とかとお話ししてたけど、


FlashみたいなWebの操作方法をまるっと無視したインターフェースがまた現れるのかなー、

殺意~みたいな話をしたような覚えがあって、



自分は、


「HTML5勢」

= WebComponentsとかShadowDOMとか、

HTMLのお行儀自体を拡張して、

その中で頑張ってモダンになろうとしてる苦労人的仕事人グループ


と、


「良いじゃんそんな構造とか意識しないでも、JSとHTML吐かれれば動くし! ははは!!」

= 最悪HTMLが形作っていた作法さえ破壊しそうな、

以前のFlashでできたサイトのような操作規範破壊を屁とも思わない

ユーザーインターフェース濫造グループ


の二つの派閥に別れるかなーみたいな予想をしている。


作法として正しいのは前者、効率は後者が圧倒的になるだろうと思っている。


この分派をしでかす大元は、

「リソース読み込みのバインディングが自動化される世界自動化されない世界

がばっちり別れる事にあると思って見てる。

自分はこれらの中間、ただし後者のほうによった形で存在したいと思っている。



CompilableWebとか

たぶん俺が言ってるだけの[コンパイラブルウェブ]って言葉があって、


Compilableな言語で書かれてCompile後はとにかくそんな感じで動くWebApplicationになるんだよってなやつで

楽なんだよ。

だってタイミングとか言語の力を使って静的にコンパイルできるんだぜ。チェックし放題だぜ。拡張し放題だぜ。(誇張と悪意がある)


もちろん前からあるけど、事情が違ってきてる。


手法がやっと光さす感じになった

浅学な自分が知る限りその走りはGなんとかって会社が買収したWebToolkitってヤツだったんだけど、

目的はともかく手段と舵取りが最悪だったので未来がなかった。


たたかう/にげる なら、「利点と能力を知った上で逃げる」を選ぶべき代物だった。


でも今度と今後はちょっと違う。2つのポイントで違う。


・言語をそのまま置換して云々的なクソッタレなアプローチをとってない。

量に比例して遅くなる度合いが酷い。つまりコンパイル/コンバートが無限に遅くなる

対応マップがないと変換されない。Latestが伸びにくい。


・変換の途中にLLVMが居る。LLVM IRがある。

IRにさえ出来れば大概なんとかなる世界になった。


LLVM IR的な未来

多大だと思うのでそっちに一回変換されてしまえばもう

なんとでもなると思う。

ほんとの資産は、LLVMへの In も Out も、全てが交換可能なところ。




結論も決着もない。


まあまだ夢で、実際に「ブラウザとそのブラウザを積んでるマシンの差」に苦しみ続ける世界がより顕著になるだけだと思うけど。

安売りされてるマシンのおぞましいまでのブラウザ性能に苦しむ人が沢山出る。


もう出てるけどもっと出る。


ともあれ第一弾はやっちまったので、楽しめそう。

楽しもう。



wrote 2014/04/10 12:17:41

UnityのWebPlayerがプラグインレスになる話


概要

Uniteでのこのセッション

Unity と Web デプロイメントの未来

http://japan.unity3d.com/unite/unite2014/schedule

Day2 room1 



実際どんな感じなの

DeadTigger2のexportをプレイする講演者のJonasさん

いい感じに動いている。



内容

JSにコンバート

C/C++ UnityEngine

C# or UnityScript UserCode


C++の変換はemscriptenで。

C#/UnityScriptの変換はIL2CPPでC++にしてemsへ。



Not yet

・ビデオ

・テクスチャ生成、プロシージャル

・.NETのソケット系(WWWだけsupported!)

・電話機能とWebCam

・Script Debug

・Exception サポ

・マルチスレッド

・AOTコンパイル限定、JIT無し

・プラグインはC++で書いてemsに喰わせる形(PureJSは無し?



感想

良い。やっとゲームエンジンでお手軽なのが来た。


なによりFrontEnd-CompilableWebだぜ、


FrontEndに対しても、コンパイル結果をデプロイできるようになる訳だ。

個人的には最高です。GWTで果たせなかったものが楽になって帰ってきた。


GWT、、GWT、、?


俺なんか言ったっけ? 幻聴じゃない?


wrote 2014/04/08 13:36:09

Unite(4/7~8)行ってきた


概要

AssetBundleWeb Deployのやつだけ真面目に書く。



AssetBundle



How Build AssetBundles

いままではWrite editor scriptsだった。

はい。大変面倒くさくてなんでなんだーー感がありました。


そして


ついに!

「行数減っていけるようになったよ。」


そうかー。


っていうかScriptが1行になって、

Manifestが吐かれるようになってた。

良いですね。


次の内容のほうが個人的にツボだったので浅く狭くなった。


MultiSceneEditing

「複数のシーンを同時にEdit可能に」

思惑と違って、エディタ内での複数シーンをHierarchy内に展開できるよ、っていう話だった。


どんな事を思い描いていたか

・現状のUnityでは、一つのシーンを開いておいて、同じシーンをバッチとかからビルドすることが出来ないが、それが解消されたかと思っていた



実際には、Editor内で、一つのHierarchyに対して、最初からLoadLevelAdditiveを行った効果が発揮できて、SceneをHierarchyに置ける、というモノだった。


これはこれで嬉しくて、LoadSceneAdditiveされたらどうなるんだろう、っていう内容に対して、

事前にHierarchyに展開した状態を確認できるし、Sceneをどう切ろうか、っていう議論がし易くなり、

Sceneの責務分解とか担当者分解に繋がってとても良いと思う。


Additiveに行う以上は、大元のSceneは存在している必要があり、

ActiveSceneという位置づけになる。

ActiveSceneをゲーム中で動的に切り替える旨味とかまで設計して考える利点がちょっと沸かない。


うん、嬉しい。いいんじゃねーか。



自分が想像してたバックグラウンドで同一シーンのビルドがバッチからできると俺がどう嬉しいか

・編集行程の裏側で、ゲームの動作を自動化したテストとか書いておいて、実際にゲームのプリプレイを行える

とか、

・外部エディタからリアルタイムにバッファをオリジナルとした本ビルドができる

とかがあった。


特に後者は、Unityのビルド機構を編集中のファイルのバッファを書き出したAnonymousなファイルから直に行いたい、という歪んだ欲望があったので、

なんとかならんかなーと思っていた。

まあなんともならんしそれはそれでいいや。

Web Deploy

http://sassembla.github.io/Public/2014:04:08%2013-36-09/2014:04:08%2013-36-09.html

wrote 2014/04/07 14:08:34

エイプリルフールに嘘をつき忘れた


概要

S2’のサービス開始しましたとか言えばよかった。


wrote 2014/04/05 21:06:44

nginxをMac OSで動かす


概要

brewで下記に入る。

/usr/local/Cellar/nginx/VERSION_OF_INSTALLED



設定

下記にできる。

/usr/local/etc/nginx/nginx.conf



単純なHTMLファイルをホスト

docrootはインストール時に/usr/local/var/wwwだよって言われてるんだけど、wwwはどことも繋がってない。

また、インストール場所のフォルダにhtmフォルダへのリンクが置いてあるけど、これも繋がってない。


インストール時に作られてるこれらのlinkは失敗してる模様。

/usr/local/var/www

/usr/local/Cellar/nginx/VERSION_OF_INSTALLED/html


んで、htmlシンボリックリンクを作り直す。



/Users/USER/Public/index.html

とかにファイルを置いて、VERSION_OF_INSTALLEDフォルダからリンクを作成しなおせばOK。


ln -s /Users/USER/Public



設定ファイルサンプル

httpとWebSocketプロキシ。


nginx.conf

#user  nobody;

worker_processes  1;


#error_log  logs/error.log;

#error_log  logs/error.log  notice;

#error_log  logs/error.log  info;


#pid        logs/nginx.pid;



events {

    worker_connections  1024;

}



http {

    include       mime.types;

    default_type  application/octet-stream;


    #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '

    #                  '$status $body_bytes_sent "$http_referer" '

    #                  '"$http_user_agent" "$http_x_forwarded_for"';


    #access_log  logs/access.log  main;


    sendfile        on;

    #tcp_nopush     on;


    #keepalive_timeout  0;

    keepalive_timeout  65;


    #gzip  on;


    server {

        listen       8080;

        server_name  localhost;


        #charset koi8-r;


        #access_log  logs/host.access.log  main;


        location / {

            root   html;

            index  index.html index.htm;

        }


        #error_page  404              /404.html;


        # redirect server error pages to the static page /50x.html

        #

        error_page   500 502 503 504  /50x.html;

        location = /50x.html {

            root   html;

        }


        # proxy the PHP scripts to Apache listening on 127.0.0.1:80

        #

        #location ~ \.php$ {

        #    proxy_pass   http://127.0.0.1;

        #}


        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000

        #

        #location ~ \.php$ {

        #    root           html;

        #    fastcgi_pass   127.0.0.1:9000;

        #    fastcgi_index  index.php;

        #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;

        #    include        fastcgi_params;

        #}


        # deny access to .htaccess files, if Apache's document root

        # concurs with nginx's one

        #

        #location ~ /\.ht {

        #    deny  all;

        #}

    }



    # another virtual host using mix of IP-, name-, and port-based configuration

    #

    #server {

    #    listen       8000;

    #    listen       somename:8080;

    #    server_name  somename  alias  another.alias;


    #    location / {

    #        root   html;

    #        index  index.html index.htm;

    #    }

    #}



    # HTTPS server

    #

    #server {

    #    listen       443 ssl;

    #    server_name  localhost;


    #    ssl_certificate      cert.pem;

    #    ssl_certificate_key  cert.key;


    #    ssl_session_cache    shared:SSL:1m;

    #    ssl_session_timeout  5m;


    #    ssl_ciphers  HIGH:!aNULL:!MD5;

    #    ssl_prefer_server_ciphers  on;


    #    location / {

    #        root   html;

    #        index  index.html index.htm;

    #    }

    #}


    server {

        listen       8081;

        server_name  localhost;


        proxy_read_timeout 500s;

        

        #charset koi8-r;


        #access_log  logs/host.access.log  main;


        location / {

            proxy_pass http://127.0.0.1:8081/;

            proxy_http_version 1.1;

            proxy_set_header Upgrade $http_upgrade;

            proxy_set_header Connection "upgrade";

        }

    }


}




wrote 2014/04/03 13:19:47

10Stock


概要

1時間以上掛かりそうな遊びの場合、

10個くらい「これが終わったら次にコレをやる」というふうに貯めてから行うと、

いい感じによどみなく物事が進む、、、、ような気がする、ということで、


なんかそんな感じの言葉を作って実践している。



効用

やる事を10個も探すと、大体探してる過程で先が見えて来て

最初の頃登録したタスクが消えたり変わったりするので楽だ。



例えば



Unity Puller

Unityのコード上のパラメータ一式を変更可能かつバージョン別に吐き出したり

セットしたりできるやつ


1. コードから変数定義とかを引きずり出す

dllから引きずりだすだけなので容易。

配列とかを直に書く奴が悪いのでそこは知らん。


2. ScriptableObjectsを吐く

型を合わせたものを吐く。domainはクラス名とか。


3. 吐き出し時のverを記入したりする


4. 固めたフォーム入りのHTMLを吐く

フォームにしないといけない。GoogleDocsとかだと死ぬので厭だ。

このへんは途中までで諦める。


5. そんなHTMLをどこかにデプロイ


6. ブラウザからアクセス


7. 入力からScriptableObjectsを吐く


8. コードに対して適応(どうやるんかなーうーん)

dllから抜き出して、コードそれ自体を吐き出させるところに介入するとか?

悩みどころ。


9. コンパイル開始

個々から先はまた別ルート




あと一つが思い浮かばないが思い浮かんだらきっと20くらいまで一気に細かくなる。


wrote 2014/03/25 10:05:44

AtomのPackageを作ってみる


概要

sendagaya.jsで @yosuke_furukawa さんのLT内容だった

Atomプラグインの作り方」みたいなのが聞けたので、調べる気力が湧いて来た。



私的な開発開始条件

以下がAPIとして存在したら頑張る。無ければ待つ。

・ToolTipがあり、スレッドセーフに呼べる

・Completionがある、スレッドセーフに呼べる



続く



wrote 2014/03/20 18:14:25

SublimeSocketAssetがCg言語のエラー表示に対応した


概要

みんないままでどうやって息してたのこの辺。


自分が担当したらツラさに気づいて、とりあえず対応できるようにした。


保存後、シェーダーコンパイルのタイミングでエラーを表示できる。

スクリーンショット 2014-03-18 1.36.57.png



スクリーンショット 2014-03-18 1.35.20.png


最近Unityさんの審査が速いので、3~5日くらいでストアに上がると思う。



動画

そのうち足す。




wrote 2014/03/18 1:37:53

Groovy用のSublimeSocketのfilter書いた


概要

以前Ruby用のSublimeSocketフィルタを書いたのだけど、

それのGroovy用を、#yokohamagroovy で書いた。

https://github.com/sassembla/SublimeSocket3/tree/master/samples/groovySample



内容

保存するとGroovyのファイルを動かす。

ファイル保存後、非同期でファイルを実行する。


実行時にエラーが出れば表示を行う。

スクリーンショット 2014-03-16 15.24.37.png



セットアップ

・Groovy入っている


・SublimeSocket3をST3のpackageに入れる


・sample/groovySample フォルダを適当にどこかにコピー


・groovyFilter.txt 内のパスを変更(runShellとstartTailing)

https://github.com/sassembla/SublimeSocket3/blob/master/samples/groovySample/groovyFilter.txt#L69


https://github.com/sassembla/SublimeSocket3/blob/master/samples/groovySample/groovyFilter.txt#L71


https://github.com/sassembla/SublimeSocket3/blob/master/samples/groovySample/groovyFilter.txt#L81


・CommandPalette > "SublimeSocket: run SushiJSON"

スクリーンショット 2014-03-13 12.58.41.png


・画面下のバーに入力窓がでるので、rubyFilter.txtのファイルパスを入れてエンター

どこか/groovyFilter.txt

これで、パスが合っていれば、以降hello.groovyを保存するごとに実行され、

エラーがあれば表示される。



今回捕獲したエラー

とりあえずク構文まわりだけカバーした。


typoとかでへんなとこにdefが来たり、

コンストラクタをtypoしたりすると下記みたいなエラーが出るので、


Method definition not expected here. Please define the method at an appropriate place or perhaps try using a block/Closure instead. at line: 8 column: 2. File: /Users/highvision/Desktop/groovySample/hello.groovy @ line 8, column 2.


とかが発生したら、原因箇所をこれでもかと赤く囲む。



やらなかった事

groovyさんはかなり頭がよく、

例えばメソッド名typoしちゃったりすると、

groovy.lang.MissingMethodException: No signature of method: Greet.sayHello() is applicable for argument types: () values: []

    at Greet.salute(hello.groovy:15)


というエラーとともに、

Possible solutions: salutde(), split(groovy.lang.Closure), asType(java.lang.Class), wait(), wait(long), use([Ljava.lang.Object;)


とか出してくれるので、関連性がログから拾えれば

quickFix とかも組み合わせで出せるなーと思ったんだけど、


まあデモだし。(逃げた)



wrote 2014/03/16 15:21:42

SublimeSocket Rubyの実行とRuntimeなエラーの表示


概要

サンプルとして作ってみた。

Sublime Text でコードを保存すると、shellが走ってRuby実行、

エラーが出ればコード上にエラー行を表示する。




サンプル一式

コードとか一式がSublimeSocket3 のフォルダ内に入っている


hello.rb


log.txt


rubyFilter.txt

保存時のエディタ挙動


各ファイルをみていく。


hello.rb

# show runtime error when save. see ./rubyFilter.txt


pauts "hello world"




実行対象のルッビファイル

いきなりtypoがあり、実行時にはエラーを吐く。



log.txt

実行ログが吐かれるところ。


rubyFilter.txt

// use RuhSushiJSON for running.

// this file is writtern by SushiJSON-lang (https://github.com/sassembla/SushiJSON) 


showAtLog: {

"message": "start defining for ruby."

}->defineFilter: {

"name": "rubyFilter",

"filters": [

{

// error

// e.g.)hello.rb:3: undefined local variable or method `somethingwrong' for main:Object (NameError)

"(.*?):([0-9].*): (.*) ": {

"injects": {

"groups[0]": "name",

"groups[1]": "line",

"source": "message"

},

"selectors": [

{

"showAtLog<-message": {


}

},

{

"appendRegion<-name, line, message": {

"condition": "keyword"

}

}

]

}

}

]

}->setViewReactor: {

    "react": "on_post_save",

    "reactors": [

    {

    "showAtLog": {

    "message": "saved."

    }

    },

    {

    "eraseAllRegions": {

    

    }

    },

    {

    "runShell": {

    "main": "/bin/sh",

    "": "/Users/highvision/Desktop/rubySample/run.sh"

    }

    }

    ]

}->startTailing: {

"identity": "sample ruby tail",

"path": "/Users/highvision/Desktop/rubySample/log.txt",

"reactors": [

{

"filtering<-source": {

"name": "rubyFilter"

}

}

]

}->showAtLog: {

"message": "ruby setting done."

}


でけえ。。。


保存時にshellの起動、

エラーログにtailハンドラを追加、

エラーをファイル上に表示、


の3つのリアクターを順にセットしている。

赤文字の部分にファイルパスが直書きしてある。




実行

・SublimeSocket3をST3のpackageに入れる

・sample/rubySample フォルダを適当にどこかにコピー

・rubyFilter.txt 内のパスを変更(runShellとstartTailing)

https://github.com/sassembla/SublimeSocket3/blob/master/samples/rubySample/rubyFilter.txt#L48


https://github.com/sassembla/SublimeSocket3/blob/master/samples/rubySample/rubyFilter.txt#L50


https://github.com/sassembla/SublimeSocket3/blob/master/samples/rubySample/rubyFilter.txt#L57



・CommandPalette > "SublimeSocket: run SushiJSON"

スクリーンショット 2014-03-13 12.58.41.png

・画面下のバーに入力窓がでるので、rubyFilter.txtのファイルパスを入れてエンター

どこか/rubyFilter.txt


で、以降、hello.rb の保存時に自動でに実行され、エラーがあると赤く囲んで表示される。

スクリーンショット 2014-03-13 13.01.36.png


動作は全部SublimeSocket3のAPIから実行しているだけなので、

node叩いたりgradle叩いたりも出来ると思う。

勿論ログからエラーだしたり。


以上。



wrote 2014/03/13 12:33:59

SSA 1.7.x is out! そのうちAtomにも対応するつもり。


概要

SublimeSocketAsset

http://u3d.as/content/sassembla/sublime-socket-asset/4SP


の、最新版 1.7系がついにリリースできた。


合わせて、SublimeTextのプラグインである

SublimeSocketのversionもST2, ST3版ともに1.4に上がった。


変更内容としては、どっちかというとSublimeSocketのエディタAPI機能強化と、

内部で使っていたプログラマブルな設定ファイルのDSL化、DSLとしてのパージがメインだった。

パージする過程でキバッたメンバーの手によりテストランナーが誕生するとかしてた。



DSL + テストランナーの仕様と処理系を切り出す事に成功したが、それはこちら。

SushiJSON

http://sassembla.github.io/Public/2014:02:22%2021-48-23/2014:02:22%2021-48-23.html



結果として、ST2、ST3に、動的にプログラマブルな形で新機能を実装できた。


・ログヒストリー機能の追加

・エラー表示の内部化

・quickfixの追加

・プログラマブル

・テスタブル



Unityの実行時ログのヒストリー表示機能が付いた


同じ箇所のログをヒストリーとして纏めて表示することができるので、

値の変化とかを超追いやすくなった。


ツールチップUIの有無で表示方法が変化する。


on ST3

スクリーンショット 2014-03-06 3.31.48.png

on ST2

ツールチップが無いから別ビューで出すようにした。スクリーンショット 2014-03-06 3.27.26.png

いやーーーーマジ便利っすわァーーーー

値が増えてるか減ってるか、

ココを通ったときのパラメータがどうなってるか、がコードに出せる!


エラー表示の内部化

こちらもツールチップの利用。

ST2版は別ビューででる。


複数のエラーがある場合は複数の項目が縦に並ぶ。

cutout.png

見やすさ。

なんという見やすさよ。

これがプログラマブルにフィルタとしてセットできるんだぜヒャッホウ。



quickfixの追加

おまけ程度だけど、quickfix可能であれば、該当するエラーのツールチップを押すと

quickfixが出て、修正が走る。スクリーンショット 2014-03-06 4.57.24.png


プログラマブル

これらの機構は、全部SushiJSONの組み合わせで書かれている。

マッチさせたいエラーの定義も、マッチ後どんなAPIをぶったたいてどんな値を使いたいかも、

JSONみたいな書き方で動かせる。

スクリーンショット 2014-03-06 11.05.50.png

例えば、

・エラーが出たらエディタの特定行を光らせる

・探知時のパラメータを使ってshellを走らせる

とかができる。



一番の用途は、

・エディタへのユーザーのアクション or その後のコンパイラのリアクションを元に何かする

というところ。



もちろん、保存したらコンパイル、なんかもここで実現している。


結果としてタスクランナーみたいなのも可能だけど、ちゃんと特化した奴を使うのが良いとおもう。

ドキュメントはSublimeSocketに追加中。 API名と出力パラメータをリスト化すればDone。


テスタブル

テストできる項目の都合で、ほぼST3専用だが、


ST3にSublimeSocket 1.4.0 を入れた状態で、


sublimesocket test


で、テストが走る。

ツールチップとかめっちゃでる。

これ。

https://vimeo.com/85882769

スクリーンショット 2014-03-08 8.09.17.png





Atomに向けて

SushiJSONは実行系がわりと小さく書けるので、Atomでも動かす事が出来ると思う。

魅力的なツールチップとかが出て来たら対応する。


wrote 2014/03/08 8:09:54

おすしのしおり

前置き



諸君、私はスシが好きだ。

諸君、私はスシが大好きだ。


回転するスシが好きだ。

回らないスシが好きだ。

ランチで出てくるスシが好きだ。

家で作るつたないスシが好きだ。

カウンターで調子に乗って後で青ざめるスシが好きだ。

そんなに好きじゃないネタを頼んで後悔するスシが好きだ。

食べ放題で出てくる疑問符付きのスシが好きだ。


関東で 東北で

国内で 欧州で

圏内で 圏外で

海上で 空中で

ダイエット中で 健康診断後で


この地上で行われるありとあらゆるスシ行動が大好きだ。



諸君 スシゲート諸君

我々は一体何を望んでいる?


更なるスシを望むか?

一切の妥協のないスシを望むか?

金銭感覚の限りを尽くし、三ヶ月分の食費を費す、嵐の様なスシを望むか?



『スシ! スシ! スシ!』



よろしい、ならばスシだ。






スシゲート 2014 社員総会 「禅」巡礼


作戦時間


date:2014/03/08

time:0900~1500(JST)



集合地点/時間


新宿駅小田急線 ロマンスカー乗り場

2014/03/08 0900(JST)

なぜこんなに早いかというと、

禅の開店前に到着して並ぶため。




道のり


(往路)新宿->ロマンスカー->小田原->タクシー->

(復路)新宿<-ロマンスカー<-小田原<-タクシー<-




必要物資(単位:¥)


ロマンスカー 片道: ¥870(特急料) + ¥1,150(乗車料) = ¥2,020

巡礼費:不明(¥6000~一万円いかないくらい)



参加人員(fixed)



チケット席

行き:

 9:30新宿発

はこね11 9号車 3C,D,4C,D



帰り:


帰りのチケットは購入してません。

現場で到着時に現地調達とします。


14:35小田原発、くらいが濃厚。

小田原からの電車は空いてるのでOKと判断しました。

間違ったらなんだ、、アレだ、ごめん。



連絡先


toru_inoue -> Twitterとか



以上!! 健闘を祈る


wrote 2014/03/01 00:00:00

SublimeSocketAsset 1.7.0 準備中でパラメータ履歴の表示が俺の中で絶賛中


概要

これの

http://u3d.as/content/sassembla/sublime-socket-asset/4SP


最新アップデート版。

やっと形になってきた。まだ出せたわけじゃない。


ST3(beta)への対応が超アツい。

俺の中で。



追加機能一覧


パラメータ履歴の表示

ツールチップを使って、

同一箇所へのログの内容を表示できる。


toriaez.png


何が凄いって、履歴ですよ履歴。単一箇所のログの履歴 = 値の変化の履歴!!!

ずっとこれが見たかった。


値の変化を、コードを通過するたびに蓄積させることができる。

いちいち「ログとにらめっこ」する必要がない。



バグ表示がステキになった

スクリーンショット 2014-02-23 18.37.12.png


今までMacのNotifierとかを使っていたのだが、

あれはなにかの間違いだった。



現在エディタで開いてないErrorとかWarningのあるファイルを開くショートカット

これも欲しかった。

保存後、コンパイルが走るが、コンパイル中にエラーが発見され、そのエラーが存在するファイルがエディタで開かれていなかったら、

現在開いているファイルの一番上にトリガーを表示、押すと

スクリーンショット 2014-02-24 0.57.22.png

こんな風にErrorとかWarningを含んでいて現在エディタで開いていないファイルと内容が表示されるようにした。

もちろん押すとファイルが開く。



エラー出てコンパイル止まる

→ どのファイルが原因かはUnityのログウィンドウ見ないとわからない

→ で、まだエディタで開いてない場合はダブルクリックしないと開かない


という地獄のような不便さから逃げ出したかった。

この辺、Unityのログ情報でコンパイル完了前に出力される情報が

Assets/以下のパスしかもっていないものだったので、しんどかった。

でもなんとかなった。SushiJSON凄い。



クイックフィックスが着いた

おまけ程度の機能しかないが、一応。

スクリーンショット 2014-02-24 0.58.55.png


適応後。 ; がつく。

スクリーンショット 2014-02-24 1.00.07.png


ほかにもquickfixの内容あるけどたぶんこれしか入らない。




こちらからは以上ですが


これらの機能を、Sublime Text 側になんの実装変更をすることもなく、

SushiJSONの記述だけでコントロールしているので、ほんと形になって良かったと思う。


これはUnity C♯に対してのSushiJSONでのエディタ機能実装だけれど、

ぶっちゃけ

どの言語に対してでも、SushiJSONでリアクターを書くことができ、

エディタの動作を定義できる。

SSAが一段落したら、Haxeのやつも公開せねば。



wrote 2014/02/23 18:37:26

JSONにルールをチョイ足しして実行できるJSON拡張記法 SushiJSON

logo.png

概要

JSON自体はそのままだと値にしかならないが、

JSONに外部文字列を与えて、単純なパーサーで実行できるようにした。


その定義とパーサーとサンプルの実行実装をまとめたものがこれ。

https://github.com/sassembla/SushiJSON



できること

・JSONの外側に文字列を追加するだけで形成可能

・自分用のAPIを定義して実行できる

・APIから別のAPIの実行が可能


なので、JSONをデータとして受取って動作する機構があった時、

・受取ったデータから特定のパラメータを取り出して動作する

みたいなのが、


・受取ったデータを元にダイレクトに動作する

という形にできる。危ない。



使用例

SublimeSocket3

https://github.com/sassembla/SublimeSocket3

Sublime Text のAPIを、この記法でWebSocket越しに実行できるようにした。

対応するSTのAPIを書き、順などを指定して遠隔実行したり、内部にフィルタなどを構築できる。



ST2用のSublimeSocketにマージ中。



記法サンプル

ファイルか、ネットワーク経由のデータで下記みたいな記法のものを送り込み

helloworld.txt or data via network


helloWorld: {←最外部はquote無し、:付き。 :以降はJSON。

"message": "hello world!"

}




実装サンプル


こんなかんじの実装を書く事で


data = ファイルデータ


def runAPI(command, params):


# print "message" value

if command == "helloWorld":

assert "message" in params, "helloWorld requires 'message' param."


print(params["message"])



// run

[runAPI(command, params) for command, params in SushiJSONParser.parseFromFile(data)]




実行結果サンプル

動作、結果がでる。



hello world!




特徴とか

JSONをAPIへのパラメータとして使用する

APIName:{JSON}



APIName: {

"key": "value"

}



APIName: から先がJSON

JSONとして解釈できさえすればOKなので、



APIName: {

"keys": [

"key1",

"key2",

"key3"

],

"values": {

"key1": "value1",

"key2": "value2",

"key3": "value3"

},

"something": [

{

"key": "value",

"array": [

"key1",

100,

false

]

}

]

}


など、配列入れたり辞書いれたり値入れたり、自由にできる。

まあこんな引数で動作するAPI厭だが。



順解釈して実行可

parserからだと、 -> で接続したAPIを順に解釈して実行できる。

単純な順実行で、値の共有などは無し。



APIName: {

"key": "value"

}

->APIName2: {

"key2": "value2"

}




ネスト可

APIの実行後、内部から次のAPIを実行する機構として、"selectors"キーワードを使用する。

selectorsの中身は順番で実行されるが、同一selectors内にあるAPI間の値の引き渡しは無し。



APIName1: {

"key1": "value1"

"selectors": [

{

"APIName2": {

"key2": "value2"

}

},

{

"APIName3": {

"key3":"value3"

}

}

]

}




API間の値の受け渡しに対してグローバル無し+明示的

selectorsを介して実行するAPIのパラメータ部分へと、キーを指定してキー+値の代入ができる。

代入するキーを明示しないと代入されない。


APIName1: {

"selectors": [

{

"APIName2<-APIName1の結果のキー": {

//  + APIName1の結果のキー: APIName1の結果

}

}

]

}



処理系実装がどの言語でもたぶん簡単

処理系はJSONのSerialize/Deserializeが用意されてる言語なら200行くらいで実装できるはず。

ジェネレータがあれば逐次実行も容易。

Pythonでの処理系はこんな感じ。

https://github.com/sassembla/SushiJSON/blob/master/parser/SushiJSON.py


動作系の実装がどの言語でも割と簡単

パースとAPIのネスト実行まで含めてこんなかんじに書ける。

https://github.com/sassembla/SushiJSON/blob/master/parser/runtimeSample/SampleSushiJSONRunner.py#L18


wrote 2014/02/22 21:48:23

Sublime Text のプラグイン書いてたらテストツールができてたよみたいな話


概要

Sublime Text のプラグインでSublimeSocketってのを作ってサーバと繋いだりして遊んでるんだけど、

それの簡易なテスト環境作って放置しておいたら、弄られて凄い事になってた。


様子

テストスイートを実行、内容に則ってエディタ側がとてもキモい動きをする。




解説

JSONを内包したオレオレDSLで、SublimeSocket APIのテストを書く。

それらを.sst拡張子のファイルにまとめて、テストスイートとして実行。

エディタ側に対して、テストスイートの各1件ずつが実行される。


フィルタをセット→フィルタに文字列を送る→hitしたらAPIを実行、

ファイルを作る→ファイルに書き込む→消す、

ファイルを作る→ファイルの特定箇所を選択する、

ファイルを作る→ファイルの特定箇所を選択する→書き込む、

バッファを作る→バッファの特定箇所を選択する→書き込む、

ダイアログを出す、

ツールチップを出す、

以上を連鎖させたり連動させたり。


入力側から最終出力される値までで管理し、assertなどでチェック、結果比較をしている。

Sublime側に対してどうしても人間がキー入力する必要がある部分(GUI、ツールチップ選択など)があり、

そのあたりは今のところ手で押している。

ムービー中で流れているテストは90件くらい。オールグリーンヤッター!


今後

テストスイートが作られた段階で、SublimeSocketのAPIはSublime TextのAPIを仮想化していて、

他のエディタでの同様の機構を呼び出す事も可能になっていた。


とりあえずVim版とかLightTable版を書いてみようかな。

wrote 2014/02/05 19:18:06

モデラーにしか通じない、言語を素材に例えてみる話


概要

模型作ったりプロダクトのサンプル作ったりとかする時、

いろんな素材、いろんな材料があるよねー、

で、その辺、言語を素材に例えると何になるだろう、みたいな話。



Java

ガンプラ + 建材用ポリパテ。

硬化までが速い、出来上がったものが研磨に耐えうる、などのメリットはあるが、

パーツの形状が決まってる事によって構造の自由度が制限されていて、

「ここにファンネルを浮かそう」

「夢は寝て見ろ」

みたいな感じ。無理なものは無理。

ただ、ボールジョイントとかの規格のおかげで全体の規格化が楽で、規格の上なら交換やパーツ追加が容易。

プラで出来てるので10番台のヤスリでの研鑽にも耐えうる。

仕上げには600番台で水研ぎしよう。


綺麗な面を作る事が出来るので、塗装も可能。MAX塗りとか。


パーツの追加に対して、規格が強力ゆえの規格自体の物理的な重量限界があり、


俺「ウイングガンダムだー! 翼モリモリにしよう!」

バタン!(荷重変化に耐えきれず後ろに倒れる

とかがある。規格自体の変更や追加は凄く大変。


そのへんに置いておくとよく黄ばむ。黄ばむと弄るのが億劫になる。

仕舞うために作った訳じゃないんですけど。



JavaScript

プラ棒と接着剤。

どんな形状でもとれるので、

「えっそんなところからこんなものが!?」

みたいなビックリドッキリメカ感が容易に出せる。

面が存在せず、点と接続線だけで全体を作る感じ。

安価かつ軽量でどんな形でも作れるけど、

いざ改造するべーって時にどこに荷重かかってるんだかわかんなくなる。

新たに作った方が速い。


影絵につかったりとか予想外の用途も多い。



Python

0.5mmプラ板と接着剤。

面での接続や構成が可能。

面であるぶんだけ、隙のない立体物を作るのがちょっと面倒くさいけど、

わりかし簡単に大規模なものが作れるイメージ。


ただ、面で囲まれた部分がどうなってるかに大変困らせられる事が多い。


面の構成強度自体がそんなに高くないので、開けてなんか入れるのは簡単。

最悪上から別の面を貼ってしまえばいい グワーッ


0.5mmとわりかし薄いので3次元曲面も作れる。

作れるけどお前それどうすんの? 左右逆のパーツ作りにくくねえ? みたいなことが稀によくある。



Scala

インダストリアルクレイと未知の耐研磨素材。

マッシブなパーツをつくることが出来る+その形状変更、接続が容易。

ただし、冷えきったインダストリアルクレイを変形させるには、相応の熱量が必要。


デフォルトがちょっと固いので、造形に腕力が要る。

反面、細い部分にも信じられない強度が出る。こどもにささる。


表面が耐研磨性を備えるので、面がものすごく綺麗に作れる。



Ruby

粘土。

ルールや規範となる台座が必要で、小さなものなら精巧に作れるが、

大きくなってくると自重でへたる。

へたらないように作るには、広い土台の確保と、立体的になってきた時の応力分散などを自分で頑張る必要がある。

ほかの粘土と混ぜても全然問題ないところがスゴい。



PHP

海辺の砂浜の砂と水。

とりあえず見れるようになるまでが速い。わーい お城! お城!!


基本積んでくだけなので、形状をあとで変更したければ、粘土とは比較にならないレベルで厳格なルールが必要。

重力があって、風が吹いてて、硬化剤は無い。


何も考えずに上から別パーツを積むと下が崩れる。あと、混じって何積んだかわかんなくなる。

硬化剤のつもりで水をかけると、染み込んでほしくないところまで恐ろしく浸透していく。


水がしみ込みきった砂を使おう。初めっからだ。

あらかじめ「コレをしたら殺す、誰であろうとだ」みたいなルールブックと、違反者がいたら即座に殺しにいくライフセーバーがいるとよい。


あと、ひとたび波が来ると夏が終わる。

ひと夏の恋とバーベキューしたい。

その後二度と遭いたくない。



C++

光造形機か金型と液化ダイヤモンド。

人間が手でどうこうするものではないのでは、、ウッあたまが

3Dデータをつくればいいのよ、提督!!

他のでプロトタイプ作ってこいつでリプロダクト、

商品ラインにのっかるのはこいつで各所がレインフォースされた何か。


凄まじい荷重や衝撃に耐えたりする。ゆえに、こいつを一方的に研磨できるヤスリはない。

魂で削って魂も削られる。


NASAで開発された。



Obj-C

1mmのプラスチック版と10mm径の針金と軽量コンクリと念力。

頑丈で耐研磨性のある面がつくれる素材と、どうあっても変形しない不思議な物体と、それを浮かせられるだけの頑丈なライン。

物理法則を若干無視した配置とかが可能。


ファンネル可。

超次元ジオラマ可。

遠隔での動力伝達可。


ただし相応にマニアック。

モノを作るのは簡単なんだけど、海底とか宇宙空間など限られた場所でしか使えない。




みたいな。

wrote 2014/02/01 11:10:35

iOSのブラウザでブックマーク押したらMacで開くやつ


概要

欲しかったので作った。

この機能Mailboxについてほしい。



内容

・クライアント(mobile)からブックマークでJSが叩かれる

・どっかのpub-subサーバにアドレス情報が送られる

・特定のMac側で受け取って、アドレスからサイト表示


かんたん!!



前提

頑張りたくないし別のマシンからも見たいので、


・iOS側で適当なサイトを見ている

・Mac側で特定のサイトを見ている



要件

・Parseでやる

頑張らないで済みそう。


・pubsub部分はPubnubを使う

Parseから使えるから良さそう。

死霊:https://parse.com/questions/combine-parse-with-pubnub-pusher-or-similar-for-real-time-messaging


・(認証が無いので)いたづらされても死なない必要がある

Parseの特定のアプリが止まるだけなのでまー平気だろうきっと。



やってみた

アドレスはまだひみつ。



乾燥

WebRTCとか使うともっと楽かと思ったけどなんだかんだでWebRTCをホストできる機構を設置するのが面倒だったのではい。

Pushだけで実装した感じ。





メモ

https://pubsub.pubnub.com/publish/pub-c-/sub-c-/0/<CHANNEL-NAME>/0/%22hahaha%22

みたいなのをPubNubに送ると、通信が開始される。パラメータも渡せる筈なので、これでブロードキャストできる筈だ。

っていうかPubNubのキーも渡すようにすれば、楽に運用できる気がしないでもない。

Adを流す

アイデアとしてはあり。

知りたいAdだけという超矛盾した前提をクリアできれば。

wrote 2014/01/29 18:14:31

ヒット確認が余裕な東京と横浜とうどん県の電源カフェとか


概要

快適な電源カフェを求めて彷徨ったり彷徨われたりするので、纏めておく。


条件としては、

・そんなに混まない

・電源の使用が公的にOK

・トイレがきれい

・電源席が空いているのが外から確認できる(ヒット確認余裕でした)

・喫煙者に殺意を抱かないですむレベルで分煙されてる

店名は、それでググってヒットしたりするとなんか厭なのでそれとなく不明瞭にしておく。



東京、新宿あたり

ルノアール 新宿のヨドバシの近所店

禁煙席でイイ感じの三階席がある。

入り口が二階。分煙もうまくいってて良い。

http://standard.navitime.biz/renoir/Spot.act?dnvSpt=S0107.73



スタバ ヴィクトリアの近所店

奥のほうの席に電源あり。

なんか不人気な席らしく、よく空いている。

バルト9が近いので映画の時間待ちとかによく使う。


http://www.starbucks.co.jp/store/search/detail.php?id=323&search_condition=新宿新南口店%E3%80%80東京都&search_type=1&pref_search=&free_word=新宿新南口店&pref_code=13&city=&store_type_3=&x=-959&y=-411



恵比寿、代官山

スタバ 恵比寿の商店街店

恵比寿駅から3分くらいの商店街の中にあるスタバ。

入り口すぐ脇の席が電源あり。

空いてるかどうか確認が楽なので良く利用する。




渋谷

エクセルシオール ハチ公の近所店

1Fの入って左の柱に電源がある。

混んでるのでヒット確認重要。


http://tabelog.com/tokyo/A1303/A130301/13050554/dtlmap/


ミヤマカフェ 渋谷のはずれ店

電源めっちゃ多い。ヒット確認不要。

ただし地下。



横浜

WIRED CAFE 横浜駅のなかにいる店

店員さんとおはなし(って何)すると時間制限付きで使わせてもらえる。

席は入り口から真正面奥なので、ヒット確認がものすごく難しい。


マクドナルド 横浜駅あたり店

二階の左奥に電源がある。

比較的回転が速いので、座りやすい。



品川

WIRED CAFE 品川駅前ちょっといったとこ店

よく貸し切りになってるのでヒット確認が大事。

店の左奥側がすべて電源席。3~4人くらいで行くと大概案内される。

香川

ドトール 高松でかいへんなモニュメント横店

うどん食べにいく時の拠点。

窓際の席2つが電源あり。外からヒット確認しやすい。

wrote 2014/01/25 16:46:04

いらないけどほしい


概要

俺が俺のために俺の「いらないけどほしい」を集めました。



Stir

高さがジワジワ調節できる机

スクリーンショット 2014-03-26 20.39.43.png

http://jp.techcrunch.com/2014/03/21/20140320stir-a-kinetic-desk-startup-from-an-ex-apple-engineer-raises-1-5m-led-by-tony-hseihs-vegas-techfund/



食パン座椅子日本製

しかも低反発らしい。

Pasted Graphic.tiff

http://amzn.to/1jBu5Pd



ホイールイン原付スケボー

KickStarterの一本。めっちゃほしい。にほんだと道交法で私有地以外無理。

ac04a335e3a1b3be6ed5435a3e52bff2_large.jpg

http://www.kickstarter.com/projects/4422853/onewheel-the-self-balancing-electric-skateboard

wrote 2014/01/23 9:12:38

C++のドキュメント作るためにSphinx使ってみる(嘘)


概要

必要に迫られたし、C++のドキュメントをSphinxで作れるって言うし、やってみる。

http://sphinx.pocoo.org



インストール

Macだと最初っからeasy_installが入っているので、

easy_install -U Sphinx


でおしまい。


brewとか使う方法もある。

http://sphinx-users.jp/gettingstarted/index.html



、、、、、と、ココまでかいて、俺が欲しいものはもっと良いのが別にあったのに気づいた。

終了

wrote 2014/01/22 15:51:37

UnityTestについて


概要

AssetStoreにある、UnityのTestToolっぽいもの。

実際にはなんなんだろう?

実機だとどう動作するんだろう?


これは何?

Assertion、



Assertion Componentってのがあってイイ、、とおもうんだけど、うんまあ、、はい、、

Unity使ってて不満だったのが、デフォルトのAssertionメソッドが無かった事。

gameObjectに対してセットするComponentとして、条件を指定する形式の実装がなされている。


Componentとして実装されているので、コードベースでやるよりも

・いつのチェックか

・何と比べるか

が、いろいろセットできてよい。

Assertionがそこかしこに書かれるよりはいい、、のかなあ。

ちょっと解んないよ。



Assertionすると実際どうなるの? AssertionのExampleを実行してみる

Assetを入れてみると、Exampleが2つ入っているので、見てみる。

スクリーンショット 2014-01-14 11.10.37.png

AssertionExampleScene.unity を開いてプレイすると、

ボールが画面奥に転がっていって下記Assertion fail の群が出る。


AssertionException: Sphere assertion failed.

(Sphere (UnityEngine.GameObject)).gameObject.renderer CompareToObject (Main Camera (UnityEngine.GameObject)).Camera failed.

UnityEngine.Debug:LogException(Exception, Object)

UnityTest.Assertions:CheckAssertions(AssertionComponent[]) (at Assets/UnityTestTools/Assertions/Assertions.cs:61)

UnityTest.Assertions:CheckAssertions(AssertionComponent) (at Assets/UnityTestTools/Assertions/Assertions.cs:16)

UnityTest.AssertionComponent:CheckAssertionFor(CheckMethod) (at Assets/UnityTestTools/Assertions/AssertionComponent.cs:260)

UnityTest.AssertionComponent:Update() (at Assets/UnityTestTools/Assertions/AssertionComponent.cs:156)

Sphereとcameraに関するassertion fail


AssertionException: Sphere assertion failed.

(Sphere (UnityEngine.GameObject)).Transform.position.y CompareToObject (Plane (UnityEngine.GameObject)).Transform.position.y failed.

UnityEngine.Debug:LogException(Exception, Object)

UnityTest.Assertions:CheckAssertions(AssertionComponent[]) (at Assets/UnityTestTools/Assertions/Assertions.cs:61)

UnityTest.Assertions:CheckAssertions(AssertionComponent) (at Assets/UnityTestTools/Assertions/Assertions.cs:16)

UnityTest.AssertionComponent:CheckAssertionFor(CheckMethod) (at Assets/UnityTestTools/Assertions/AssertionComponent.cs:260)

UnityTest.AssertionComponent:FixedUpdate() (at Assets/UnityTestTools/Assertions/AssertionComponent.cs:162)

SphereとPlaneのposition.yに関するassertion fail


これらは、SphereのInspector上で、コンポーネントとしてセットしてあった。

Sphereのコンポーネントに下記2つのAssertion設定がある。

スクリーンショット 2014-01-14 11.20.50.png


なるほどなー。SphereとMain Cameraとか、SphereとPlaneを比較して、

それぞれのプロパティの何がどうなったらダメ、とかを指定できる形。


Assertionのバリエーションはこんな感じ


何を比較するか

スクリーンショット 2014-01-14 11.33.51.png

いつ比較するか

スクリーンショット 2014-01-14 11.33.56.png



試しに、SphereにSphereScript.csというスクリプトを新たにくっつけて、

パブリックなVector3のパラメータ myVector3 を実装してみたうえで、

スクリーンショット 2014-01-14 11.37.30.png



Sphereにアタッチ + AssertionComponentを付け加えたところ、

スクリーンショット 2014-01-14 11.41.38.png


確かに、SphereScript.myVector をターゲットに指定して、Nullじゃないよね!? みたいなチェックができる。

スクリーンショット 2014-01-14 11.39.30.png

で、実行してみると、

チェックのタイミングをStart時にしたので、もちろんNullなmyVecotrのAssertionは失敗、下記が出た。

ArgumentException: Null was passed to a value-type argument

UnityTest.ComparerBaseGeneric`2[UnityEngine.Vector3,UnityEngine.Vector3].Compare (System.Object a, System.Object b) (at Assets/UnityTestTools/Assertions/Comparers/ComparerBase.cs:113)

UnityTest.ComparerBase.Compare (System.Object objVal) (at Assets/UnityTestTools/Assertions/Comparers/ComparerBase.cs:44)

UnityTest.ActionBase.Compare () (at Assets/UnityTestTools/Assertions/Comparers/ActionBase.cs:30)

UnityTest.Assertions.CheckAssertions (UnityTest.AssertionComponent[] assertions) (at Assets/UnityTestTools/Assertions/Assertions.cs:32)

UnityTest.Assertions.CheckAssertions (UnityTest.AssertionComponent assertion) (at Assets/UnityTestTools/Assertions/Assertions.cs:16)

UnityTest.AssertionComponent.CheckAssertionFor (CheckMethod checkMethod) (at Assets/UnityTestTools/Assertions/AssertionComponent.cs:260)

UnityTest.AssertionComponent.Start () (at Assets/UnityTestTools/Assertions/AssertionComponent.cs:103)


インスペクタは別途あり、そこから一覧をみることができる。

適当なIdentityになりうる文字列とかを入れさせてほしいなーっ、、て思うが。


Assertion感

Good:

オブジェクトに対して制約を付けられる

タイミング系とかを細かくセットできるのはうれしいなって。


Bad:

AssertionのIdentityが付けられない。

コメントはそれ単体でエラーにならないので否だけど、

自分は「このAssertionに失敗するってことはこういう不味いことが起こってるんだぜ」とかを、Assertion失敗時に表示したいなー。


たとえば、

Assert(0 < A.transform.position.z, "一瞬たりともAのz位置が0とかマイナスなんてありえない!!" );


みたいに書きたい。

Assertion Fail 時には、

Assertion Failed: "一瞬たりともAのz位置が0とかマイナスなんてありえない!!"とか出したい。

これはComponent上でセットできても良いと思うんだけどなー。



つづきはまた今度書く。

wrote 2014/01/14 10:59:02

2014持ち運んでるものリスト


概要

t_wadaさんの鞄ばなし記念。

なんとなく纏めとく。


傘とかはマジで便利なのでオヌヌメ。



package

GERRY GE3004 デイパック M 【14L】// 軽い、口がでかいので割となんでも入る、防水、袋状なのでなんでも放り込んでおける、など。

otoko-style_gerry-ge3004.gif

ただし、経年でチャックがぶっ壊れるバグがある。防水なのでまず直せない。

年々スペックが上がっていくので今年の奴はいいかもしれない。



include

/PCバッグ // 衝撃吸収用。


MBA 11inch 2013 // 軽い。

design_multitouch.jpg

/iPadバッグ // 衝撃吸収用。


iPad Air 2013 // 紙のノート類すべてと引き換えに入れた。

a.png


/ケーブル缶 // かさばる小物は携帯用タバコ吸い殻入れに入れると捗る。タバコ吸わない。

box.png


以下中身

d.png


Lightning Cable // 最低限必要。


電源タップ  // 1口 -> 2口 という最小のもの。


Square // 決済のアレ。


VGA変換 // 急なプレゼンとか、勉強会とかで発表するときに割と使う。


USBメモリ 16G // 緊急用。フタに着いてる。

ねりけし // デッサン用のもの。


MagSafeコンバータ // だいぶ使わなくなったけど万一に備えて。



MBA電源アダプタ // 延長ケーブルは無し。


Micro USB Cable // 10cmくらいのやつ。


傘 Ofess is.a.brella // 雨が降ってても折り畳めばプラスチックのパックに仕舞える。

ofess01.jpg


/カバンの中身 // ペンを入れるところがあって、カバンの中で位置が固定されるので楽。いらないポケットは空のまま。

photo_p1.jpg

http://www.kabannonakami.com/item/b4/b4.html


以下中身



ボールペン x 3 // 4色のもの。ドカッと買っておくと良い。予備だらけ。

ballpen_080130.jpg


ペンカッター // 割と使う。

rep99.JPG


折りたたみはさみ // 使う。ペンの太さになるので、ペン入れ部分にさしておけるのが良い。

url.jpg


iPad用ペン // iPad AirでのPaperが快適すぎて、あんまつかわない。まれによくつかう。

images.jpg


シャーペン // 極まれにつかう。

images.jpeg




他、財布、パスポートとか。



シメて2kgくらい。




wrote 2014/01/09 18:24:27

UnityでCrashLogをアレするCrittercism


概要

ユーザーの手元で起こってるデバッグログと向き合おう。


まあ必要だよね + 自分たちで作るの面倒くさいよねということで、ありもののサービスを使う。

ユーザー側で発生したエラーとかログをサーバに送付して集計してみせよう、 みたいなの一杯あるけど、今回は特にCrittercismを使ってみた。


Crittercism

https://github.com/crittercism



他の手段

選択肢は多く持っておこう。

ということで、こんなのもあったのを紹介。

BugSense

https://www.bugsense.com/


おなじようなサービス。

登録の入力フォームがクソだったので却下した。



Crash Reporter

http://u3d.as/content/jeff-brown/crash-reporter/4AH


アセット。ログが発生したら、メールでぶん投げる。

$10とのことなのでまあ、はい。小規模ならいいのでは。



今回の用途

・iOS/Android用に作ったUnity Appがユーザーの手元でどう動いてるか気になるよね。

・Unity Editor用に作ったAssetが使用者の手元でどう動いてるか気になるよね。

自分の場合、後者の用途がより気になったりする。

UnityのEditor用AssetのクラッシュレポートにCrittercismを使うよ的な。


両方書くけど。



iOS/Android 用

Crittercism自体はUnity iOS/Android 用のプラグインを配布してないけど、Github探したらあった。

ちゃんとCrittercism製。


iOS用

https://github.com/crittercism/crittercism-unity-ios

Android用

https://github.com/crittercism/crittercism-unity-android


で、うごかしてみたところ、Unity4.1までしか対応してない挙動してた。

お問い合わせ中。



Editor用

Web用のものがそのまま使えた。

こいつをAsset store にアップするかどうかは、調整中。


wrote 2014/01/07 19:18:04

俺以外引っかからなかったであろうAppleTV関連の何か


概要

Mac mini にMBAとかノートからリモートログインして、

そのへんのAppleTV へのミラーリングをしようとしたら、ダメだった話。



症状

Mac mini からのミラーリングが、バッファがぶっ壊れた画像として表示される。

つまり、見れない。。。 つらい。。。。



原因

そもMac mini に何のディスプレイも繋いでおらず、

かつ手元のMBAからのリモートログインだったため、

・Mac mini からのディスプレイ出力先がUnknown扱いされる

・Mac mini からのミラーリング対象としてUnknownなviewが無視される

・Mac mini のサブディスプレイという名目でなんも映らんviewがAppleTVに表示される


というものだった。



解決法

まだ試してないけど理屈的には何とかなるだろうなーって感じになったので、メモまでに。

Mac mini とどうでも良いディスプレイを繋いでおくとか、

どうでもいいディスプレイ認識される何かを繋いでおくとかすれば良いんだと思う。


→で。


上記方法で解決できた。

・リモートログインは画面に数えられない

・無画面状態だとAppleTVへのミラーリングが失敗する

という内容で、ファイナルアンサー。


2014年もよろしくおねがいしますですしお寿司。

wrote 2014/01/05 17:59:53

[忘年会議, はくらい提督, Haxe->Unity エディタの準備中]


概要

忘年会議スタッフの皆様、素晴らしい忘年会議をありがとうございました!

来年も来たい。



タイトル前半に意味はありません。あった事を配列に入れただけです。



HaxeがUnity用のコンパイルに対応したとの事で、動かしてみる。

最終目的としては、SublimeSocketAssetの Haxe -> Unity対応版を出す。


日本語の情報源はここ

Haxe Advent Calendar 2013の14日目の記事

Unity4.3新機能とか Haxeで何かつくったはなし。(前編 : Haxeビルドまで。)

http://qiita.com/nobkz/items/ce6bbf56d0f0cbad2e13


とっても参考になる記事だった。

@hakurai 提督に教えていただいた。

ちなみにこの記事で使っているHaxe->Unity変換のさらに元ネタは下記。

https://github.com/AxGord/hx-unity3d



Haxe、入っていますか

もしインストールしていなければ、

homebrewにも対応している。ので簡単に入る。


brew install haxe


/usr/local/include のパーミッションによっては、link作成に失敗するので、

フォルダの権限とか弄ってやると良い。



haxelibについて

インストールして最初の一回は、setupを行わなければいけない。


haxelib setup

その後はアドベントカレンダーにそのまま従う感じ。


一応実用可能か確かめたときのブツ

下記に上げておいた。

https://github.com/sassembla/Haxe-Unity



アドベントとの差分としては、

Haxe側でコンパイルする必要ない(っていうかエラーが出まくるだけ)ので、build.hxml -D no-compilation を付記した。

build.hxmlを調整して、csファイルの吐き出し先をAssets以下にするようにした。


build.hxml

-D no-compilation

-lib unity3d

-cp src/

-cs ../Assets/cs

MyClass


Assets直下に出来るフォルダの名前も、なんか考えた方が良いかもしれない。


自分のやりたい事=Haxe->C#->Unityで実行した際のエラーをHaxe上に吐く

いろいろパーツ探し中。

HaxeからC#を吐いて、Unityでコンパイルしたり動かしたりしたときのエラーログとかを、

Haxeのコード上にマッピングしたい。


こういうのが必要。

コード:

Haxe -> C#( + compilationTargetMap) -> Unity Compilation


エラー:

Haxe <- C#( + compilationTargetMap) <- Unity Compilation

<- コンパイルエラー発生

<- C#上のエラー情報

<- Haxe->C#への変換マップ

<-Haxe上へのエラー表示


ということで、上記の中の矢印、

<- Haxe->C#への変換マップ

が必要。



Haxe -> JavaScript とかだと、ソースマップを吐く機構が備わってるのでいいんだけど。

http://haxe.org/doc/js/source_debugging


他の言語だとどうなってるんだろう。Haxeがその辺標準で持ってると嬉しい。


@hakurai 提督に、(忘年会議後に香川まで拉致って)お話を伺ったところ、

Haxe -> Java 機構で、Java化後のコンパイルは必要な筈なので、

Javaのコンパイルエラーが出る -> Haxeコードのこのへんだよ、って機構は存在する筈。

というステキなお話をいただいた。

やってみんべー。


wrote 2013/12/14 22:39:31

オレオレAssetをAssetStoreに出して死なないために気をつけること


概要

みんなだいすき Unity Advent Calendar 2013 案件。


前日 13日は、

shinriyo@github さんの

せっかくだから俺は13日の金曜日を選ぶぜ!ランキング機能の簡易実装したけー。 

でした。


で、今日は俺 @toru_inoueです。


カレンダー上だと、

スクリーンショット 2013-12-12 19.04.31.png

Sublime TextでのUnity作業の効率化について


と、言ったな。


あれは嘘だ



Unity使いなら誰もが世話になっているであろう AssetStoreに、

オレオレAssetを登録するときのAssetのおすすめ構成とか、やっとけポイントについて書く。



登録に関しては以前書いてるんだけど、今回は


どういう構成のAssetを作ると、使い手側としてまだなんぼかマシか

どうすれば審査をするUnity側にポカーンとされないか


みたいな話にするつもり。


ソースはSSA。

SublimeSocketAsset

http://u3d.as/content/sassembla/sublime-socket-asset/4SP



これからAsset売ってやるぜー!! みたいな誰かの参考になれば。



1.Asset名のフォルダをきっちり切ろう!

登録するAsset名で プロジェクト/Assets/ 以下にフォルダを切っておくと凄く良い。

こんな感じ。

p.png

できるだけ全てのものをAsset名フォルダに納める。

できるだけ Assets/Standard Assets フォルダとか Assets/Plugins とかを汚さないようにすると良いと思う。



ログ出力したり、辞書ファイル作るとか、Assetとして動作する上でしょうがなく汚すとしても、

自作フォルダ内、ようは自分の作ったAsset名フォルダ内に絞れるようにしよう。


フォルダ名で判断してビルドフェーズが異なってくる系のものも、大概は自前のAsset名フォルダ下にネストしてもなんとかなる。

参考:http://wiki.unity3d.com/index.php/Special_Folder_Names_in_your_Assets_Folder

☆Standard ~ 系とかだけは、どうしようも無い気がする。Assets直下でないと作用しない。

ので、このへんは「つかわねーように心がける、設計を変える」とかが最適解な気がする。

未来の変更の可能性を殺してはならない。


このへんのはみ出し具合が最悪だと、


Plugins にいろんなものが置いてあるわ、

なんだかわからないけど外部に謎の名前でフォルダ吐いたりするわ、

勝手にファイルが書き変わったりするわ、


そのAssetのUpdateがあったときや、そのAssetを使うのをやめたいときに、


「あれ、どのフォルダがAsset由来のやつなんだ、、!? 消していいのかコレ、、?!」

「なんかファイルがいつの間にか上書きされてるんだがァ、、!?」


みたいになり、ガチ欝感全開になる。

で、憎まれこそすれ、ユーザー = 開発者が幸せになれるわけない。


当然、開発者が幸せになれなければ、

Assetの開発者にも幸せは訪れない。


AssetStoreに限らず、この世にはそういうこと考えずに、

ガンガンPluginフォルダを汚すようなSDK配ってるゲームプラットフォームとか、SNSとかが、数多ある。


もーね、殺意駆動が全力全開だよィ☆


メンテするのは自分じゃなくて、自分を含んだ誰か、なので、憎しみを生まないように気をつけよう。


2.メニューバーは共有資源なので大事にしよう

メニューバーに自前のAsset用の項目をのっけてて、Unityの審査に落ちた事がある。


~ある日~


Unity 「Your Asset has been declined! ウェヒッww」

「D、、、Decline、、だと、、!? なんでなんだ Unityィィィーッ!!」


Unity Please nest your extension under an already existing MenuItem rather than creating your own!

「はい。」




見てみるとまあ、、はい、、



何も無い状態

a.png


+ NGUI

b.png

+Facebo、、、

c.png



―――のびるッ!!(CV. 子安武人)

そしてバーの幅は有限なので、右端のものが見えなくなっ、、なっ、、、



あれだよ、Xamarinとかでよくあるやつだ。

スクリーンショット 2013-12-13 23.56.24.png



ぶっちゃけ、ショートカットを決める + Assets とか Window に突っ込む、というロジックで大概のものは良い気がする。

GUIでのアクセスが多量だったり、表示し続ける必要があるなら、それ用のPaneとかPanelを持つ事を考えた方が良いだろう。


というわけで、

オレオレMenu項目、格好悪い。 なるべく使わないで済む方向で考えよう。


3.READMEをしっかり付けよう!

直感的にAssetのすべてがすぐ使えるならまだしも、

いろいろなAssetが存在してるので、その使用法や常識など、

コモンセンスが全く無いと思ってもらって良い。



・どうやってインストールすればいいのか

・何をすると何がどうなるAssetなのか

・どういう風に動いているのが正常なのか

などを、Assetの使用を通じて説明する必要がある。

Assetを紹介するサイトっていうかAssetStoreで見せておくのも尤もなんだけど、

ユーザーがUnity上で使うときにどう迷わないようにできるか、というのが本懐なので、

READMEを用意するとか紹介ムービーへのリンク用意するとかAPIリストを用意するとかしよう。


添付の資料の更新手段がUpdateしかなく、再申請に時間がかかることを考えると、

・リンクが書いてあるファイル

・リンク先はどっかWebSite

みたいな構成にするのが一番楽だと思う。


SSAだと、インストール法とかに最新のSublime Text とかSublimeSocketプラグインが関わってくるので、

そのへんをWebにぶん投げるようにしている。



4.連絡がつくようにしよう!

当然っちゃ当然なんだけど、サポート用に連絡がつくアドレスとかTwitterアカウントを、

目につくところに書いておく必要がある。



SSAでは、README内にTwitterアカウントとメールを明記しているけど、

公開してからいままで10数件くらいのお問い合わせがメールで来た。


機能の追加要望とかもメールでくるのがほとんど。


使ってくれる、要望をくれるひとがチラチラいるのはうれしい事です。はい。

バグ報告がメインの用途だけどな。



5.フォーラムに乗り出そう!

Unity AssetStore フォーラムみたいなところがあって、

いろんなAssetが「俺、これの作者なんだけど聞きたい事ある?」みたいな感じで書き込んでいるので、

真似れば良いんだと思う。特に損は無さそう。


http://forum.unity3d.com/threads/217116-SublimeSocketAsset?p=1451794#post1451794


っていうか自分もさっき作った。



6.どのくらい儲かるのか

グへへへへへへへへへ、、、(ゲス顔)

お察しください。


自分は、少なくとも月の食費は賄えている。



ということで、

AssetStoreにAssetを登録してみて、あーこれ必要だなーって思ったことなどを纏めてみた。

どうすれば売れるか、みたいなのはもっとマジメな人がきっと話してくれると思う。



おまけ

Unityさん、なんかHaxeのターゲットになったそうで、


Haxe書く→Unity用の何か(C#)にコンパイルされる→Unityで動かせる

みたいな時代がくるらしいようなアトモスフィアっぽい。


で、SublimeSocketAssetをHaxeからの連携込みでやれるようにしてみると楽しいのかなあと思ったり。

すこしだけお金のにおい。


個人的には、

Haxe -> C# -> Unity -> PNaCLとか、

TypeScript -> CLI -> PNaClとかのカオスきわまりない流れに身をぶん投げようとしている友人がいるので、

エディタ周りでちょっと参加してその行く末を見守ろうかなーと思っている。


あわよくば TypeScript -> CLI に対してエディタ拡張とかで絡みたい。



明日は、nobkz さんです。

Unity Advent Calendar 2013


wrote 2013/12/14 00:00:00

【解決した】UnityのWWWで、ファイル送付時にヘッダー情報付加不可みたいな話


概要

WWWで、サクっとファイルアップロードするサンプルを書こうとして詰まったのでメモまでに。


そもUnityでWWWを使うのが悪手なんだけど、WWWForm.AddBinaryData(…) みたいなのを見かけて、

ああー簡単に書けるんだろうなーきっと、って思ったんだけど、そうでも無かったんだぜばなし。

↑2014/01/30 1:12:48 書き方変えたらちゃんと動いた。 一体何に嵌っていたんだ俺は、、、

参考:

Unityでtwitterに投稿する方法(API1.1)

http://zi-su.blogspot.jp/2014/01/unitytwitterapi11.html



実装

下記はOK.


var data = 何かbyte[]なデータ;

var name = "something.type";

var dataType = "application/type";


WWWForm form = new WWWForm();

form.AddBinaryData(name, data, name, dataType);

var www = new WWW(url, form);

はー簡単っすねえ。

通信も簡単に成功する。 multipart postが走る。



で、じゃあheaderに細工しようー、と思ったんだ、


headerに key:value みたいなのを入れてみようぜーって。

var data = 何かbyte[]なデータ;


WWWForm form = new WWWForm();

form.AddBinaryData(name, data, name, dataType);

var www = new WWW(url, attachData, headers);// こういうのがあれば良いよね


ところが、attachDataを受け入れるスロットが、WWWのコンストラクタには無い。

WWW(url, data, headers) っていうのはあるけど、dataはbodyの中身になるものだ。


っつーことは、WWWForm.AddBinaryData 以外に、ファイルアタッチを行う手段は無いのか!?


→ドキュメント見たけど、無いような気がする

→じゃあ WWWForm.AddBinaryData した後に、formにheaderの情報を足せれば良いんですね!



結果

→じゃあ WWWForm.AddBinaryData した後に、formにheaderの情報を足せれば良いんですね!

そんな方法は無かった。


原因

1.ファイルアタッチを行うルートは、WWW(url, form)しかない。

2.WWWFormの内部のheaderは form.headerでアクセスできるけど、writeは出来ない。


よって、ファイルアタッチの時、WWWクラスを使う以上は、headerに何かの情報を足す事が出来ない。


、、、なーーんか前、WWWでOAuthとかを通れるようにしたとき、似たような目にあったような気がして、

そのときはブレイクスルーがあったような気がするんだけど、、、



form.headers に書き込みできないのツラい。



誰か助けて!! @toru_inoue





wrote 2013/12/06 13:38:34

ウルトラ個人的な主観によるIDE/エディタ手触り評 中


概要

打鍵感とか、文字が現れる速度とか、

そういえばエディタごとに差を感じるなーと思って書いてみる。

主観に基づくタイプ時の文字表示即応性、入力後の抜け

という点で評価する。



文字表示即応性、入力後の抜けとはいったい

即応性:

タイプして文字が出るまでの間隔をもとにした感覚。

抜け:

文字の表示開始から完了までの感触。

いつタイプが終わったか、の打鍵後感みたいなの。



ちなみにキーリピートは設定で何とかなると思うので評価および考慮しない。


特に断りが無い場合、Win = Windows8、Mac = 10.8.5とかの環境で行ったものとする。


あと、何言ってんのこいつ、っていう意見は全面的に正しい。



テキストエディット Text Edit.app

表示即応性 5

抜け 5

可もなく不可もなく。


エディタ、、っちゃあエディタ。

plain text書くモードにすると、わずかに表示即応性が増す。


抜けは若干ヒンヤリとした光沢のある金属をなぞったような感触。

自分の場合、思考の速度にマッチするらしく、字を書きながら考え事をする時に重宝する。

急かされずもたつかず、打つのとその内容を掴むのに苦がない。



Eclipse

表示即応性 3

抜け 3

遅い。というよりより正確には、肝臓にジワジワ来る系。


水飴のような粘性の高い質感。

軽いキーストロークでヘビーブロウが打てる。ボクシンググローブみたい。


思考の上でタイプを行い、考えが纏まってからうりゃーって打つ長考スタイルと相性がいいのでは。



Vim/Emacs

表示即応性 ?

抜け ?

Terminalとかに引っ張られるので、ことタイプに対しての感覚ってのが判断できない。


Sublime Text 2

表示即応性 7

抜け 6

速い(確信


タイプから表示までの速度がかなり速く、余分なものを含まないクリアな印象。

抜けもよく、針で刺したようなタイピングになる。


反面、もうちょっと思考の時間をください、速過ぎます、みたいな感じでもある。

良くも悪くも薄い。


ゆっくりと考え事をしたいときではなく、物事に対する方策が多数あり、それらを出来るだけ速く順に試行し、

仕事を瞬殺する際に効果がある印象。


Sublime Text 3

表示即応性 6

抜け 6

まだ僅差でST2より遅い気がする。

ST2よりも若干まろやかな印象。僅差だと思うんだけど、やっぱり差を感じる。

抜けについては、差を感じない。



以下、未評価 & テイスティング中

NetBeans

まだ。



メモ帳

表示即応性 4

抜け 4

海水っぽい。

ワーイって泳いで陸にあがってから肌がざらつく、みたいな感覚。



IntelliJ系 (詳しく言語別に書きたい)

表示即応性 4

抜け 4

ソリッドな印象。遅くないが、空気抵抗みたいな重量を感じる。


なんかVSに近い。


俺、今、風を切ってる!! みたいに考える時間が出来るので、

打ちながら考える、 みたいなことが出来る印象。



MonoDevelop 4.x

表示即応性 6

抜け 4

速い。

打鍵後、表示されてから抜けるまでに若干隙がある。出の速い技で差し込んで割り込む事がry


抜けにくせがあって、

タイプひとつひとつがビニールのオセロを置くような感覚で、ペットリとしたアフターフォローがある。

このくせが好きな人とかもこの世に居そう。

3.xに関してはもう触ってないのでよくわからないけど、表示即応のところはとても良くなった。



VisualStudio20xx

表示即応性 5

抜け 4

評価中



Xcode

TextMate

禿丸


TeraPad


jEdit


JEdit


ミミカキエディット


BBEdit


TextWrangler


CotEditor


Notepad++


gEdit

wrote 2013/12/05 8:45:59

Unityでzipを使って圧縮データを作る


概要

SharpZipLibを使って、Unity内でデータを圧縮する。


下記ライブラリが有用。

https://github.com/icsharpcode/SharpZipLib



用途

書き溜めたログファイルを圧縮して送りたくなったよ!!

という異端な用途を満たしたい欲求からスタート。



手段

ローカルでファイルに吐き出す必要は無いので、

path -> byte []

byte [] -> byte []

なものをサクッと用意してみる。



コード

ビルドすると下記libができるので、

ICSharpCode.SharpZipLib.dll


これと下記コードで。


/**

compress data from path

*/

public static byte [] ZipFromFile(string filePath) {

using (var fileStreamIn = new FileStream(filePath, FileMode.Open, FileAccess.Read)) {

using (var memoryStreamOut = new MemoryStream()) {

using (ZipOutputStream zipOutStream = new ZipOutputStream(memoryStreamOut)) {

byte[] buffer = new byte[4096];


// get zipped-file name from filePath.

var name = Path.GetFileName(filePath);


ZipEntry entry = new ZipEntry(name);

entry.DateTime = DateTime.Now;

zipOutStream.PutNextEntry(entry);


int size;

do {

size = fileStreamIn.Read(buffer, 0, buffer.Length);

zipOutStream.Write(buffer, 0, size);

} while (size > 0);


zipOutStream.Finish();


zipOutStream.Close();

}

return memoryStreamOut.ToArray();

}

}

}


/**

compress data from bytes

*/

public static byte [] ZipFromBytes(byte [] data, string asName="DEFAULT_NAME") {


using (var memoryStreamIn = new MemoryStream(data)) {


using (var memoryStreamOut = new MemoryStream()) {



using (ZipOutputStream zipOutStream = new ZipOutputStream(memoryStreamOut)) {

byte[] buffer = new byte[4096];


ZipEntry entry = new ZipEntry(asName);

entry.DateTime = DateTime.Now;

zipOutStream.PutNextEntry(entry);


int size;

do {

size = memoryStreamIn.Read(buffer, 0, buffer.Length);

zipOutStream.Write(buffer, 0, size);

} while (size > 0);


zipOutStream.Finish();


zipOutStream.Close();

}

return memoryStreamOut.ToArray();

}

}

}


内容は適当なので、ブラッシュアップとかしたい。

ともあれ

path -> zipped byte []

byte [] -> zipped byte []

が出来る感じ。



アイドル自由入力行

dfgfgっhjきzdgfdfgvbhじこ


↑アイドルがかってにかきました。

wrote 2013/11/27 17:15:50

Twilioでのsmsの使い方


概要

Twilio

http://www.twilio.com

を使って、そのへんのスマフォにsmsを送付してみる。


nodeからtwilioが使えて、同じものがParseからも使えるので、足がかりにメモを残しておく。

電話とかsmsとか動かして感覚みたいときに重宝した。


今回は特にnode絡みの使い方の話。



ドキュメント

http://twilio.github.io/twilio-node/



前提条件

Twilioから外部の端末へのsms-messageを投げるために、Proアカウントと、Twilioでナンバーを買う必要がある。

つまりタダでは試せないよ!

あと、Twilioで買える日本の番号からsmsとか送るのは無理。

また、値段観的に、海外の番号だと$1/mだったのが、日本のだと$5/mだったりしたのも気になった。

手順

1.アカウント作る。最初は自動的にTrialなアカウントになる。

2.Twilioで発信用番号を買う(自分はシカゴの番号 +17系 で買った) この時点でProアカウント必須だったような。

3.番号を使って自分のスマフォとかジャパニーズな番号にsmsを投げることができる。

4.手元のnode環境にnpmでTwilioのAPIをインストールしとく

5.nodeからTwilioAPIを叩いて発信。その際、Twilioで購入してた番号を使用する。



コード

下記。

TwilioのSIDとAccessTokenが必要。

https://github.com/sassembla/Persows/blob/master/Twilio/twilio.js



Usage

nodeで適当にtwilio.jsとTwilioのSIDとかTOKENとか渡すと良い。


node twilio,js TwilioSID TwilioToken toNumber fromNumber message


e.g.

node twilio.js ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx +81xxxxxxxxxxxx +17xxxxxxxxxxx messageForYou


再三になるけど、注意点としては、Twilioで購入した日本の番号からだとsmsできない。

番号を取得する際、smsが出来るナンバーについぞ出会えなかった。


wrote 2013/11/25 18:05:52

Parseでオレオレジャーヴィスを構築してみる


概要

「~さんにコレ確認しておいて」

とか

「~にコレ見せてOKとっておいて」

とかを、自分でやらずに自動化したくなった。

つまり劣化版ジャーヴィスがほしくなった。


ジャーヴィスって何って人はコレとか見ると解るような解らないような

http://www.youtube.com/watch?v=c4BixHyBr1A



あくまで劣化版。用途特化させる。


で、Parse.comにはそれが出来るだけのものがざっくり揃っていたので、

サクッとやってみる事に。



目的->手段

コミュニケーションのすべてを自動化するのは無理なので、

人と人との間のコミュニケーションの確認を自動化する


とりあえずこのくらいハードル低くしとく。



何をもって一応の達成とするか

Please check it when you can みたいな連絡をこのサービス経由で投げて、

サービス経由で I saw it, boss. みたいなのを受け取る。


実際にはサービスにOrderを投げ、Orderが叶う = He said "I saw it." をサービス越しに受け取る、とかになる。


手段はsms、mail、telephone、なんでもいい。

相手が受け取りたい手段を一度でいいから提示してもらえばいい。


人間同士での特定用途での意思確認、意思伝達の自動化が果たせればそれでいい。

その先の、意図の伝達とかは後回し。



実装

ParseのCloudCodeの中にTwilioとの連携があったので、

サービス -> sms -> target(人間) -> 、、、みたいにしてみる。


単にメッセージを届ける + retryを自動化する所まで作る。


最終的な実装としてはParseを離れて、Push型の独立したプロセスを立ち上げる感じになる。



うれしみ

つたえること。勝手に伝わること。

伝わることと、伝わった確認が取れる事、またretry/notifyなどを自動化できることに意味がある。



既存との差

askする内容によって、[see it]って言葉の内容は変化する。

既読だからって了承してるわけじゃないし、解ったからって納得してる訳じゃない。

この辺を自動的に解決する。



ウザくないのか

わからない。ので、試し中。


おっさんにとっては、仲介に入るのは、おっさんではなく、

やはりちょびッツが至高な気がしてきた。

やはりちょびッツが至高な気がしてきた。


この辺も受け手側が選んで良いようにしようと思う。


wrote 2013/11/23 12:09:49

ぬる舗interException in thread "Shinagawa"


概要

ここが詳しい。

http://d.hatena.ne.jp/itog/


二年という契約満了のタイミングと、定員割れしててそのへんもなーという

大変高度で大人な事情により決断が下されたので、


べつに面倒になったとかそういうのじゃない。たぶんきっと。



ぬる舗クライマックスシリーズ-歳末大ガベージコレクション

みたいな感じでなんかしようと思う。

平日? 夜? ゲーム温泉の前? 後? なにも考えて無い。


ぬる舗を123Dで撮影しまくって、3D化してみるとかしてみたいような気がする。


メモリダンプみたいな。 思い出ダンプみたいな。



新インスタンス

現在の住民の中で、現状、俺にしか関係ないけど、

ぬる舗の名前だけ継いで、ぬる舗(改)みたいなのを渋谷リージョンに拵える予定です。


予定は予定。未定ではなく。


See you again, NullPointerException.


wrote 2013/11/11 1:57:29

あたまのわるいショートカットについて


概要

社内でこういうのが生まれて楽しんでいます。

・セーブ:⌘+s

・ダブルセーブ:すばやく⌘+s x 2


効果をちゃんと設定してるバカもいて、

CIのコントロールをわざわざエディタにつないで、

主にキャッシュクリアして何かする、とかに使っています。


GUIキライとかいうのもあると思うけど、、、

SublimeSocket(Sublime Text のアセット)に組み込まれているようです。



次を狙う

してやられたので、

個人的には

ヨガフレイム + ⌘ + s あたりを作ってみようと思います。


←↓→ + ⌘ + s 。 ちょうどS2'の遠隔リスタートとかが欲しかったので。


方向キーだとむずかしそう?


wrote 2013/11/02 21:32:27

こわくないScala勉強会に行ってきた


概要

http://connpass.com/event/3420/

こわくなかった(震え声涙目

陰陽とかConduitとか 感想追記する。



自分のLT死霊

自作してるリモートコンパイル機構について発表してました。

http://bit.ly/179oVbn


だいたいこんなかんじ。

スクリーンショット 2013-10-20 17.51.12.png




っていうかそれより、LTタイトルで被せてきた @tototoshi さんマジすげえ

「最高のコンパイルにしようぜ」

http://tototoshi.github.io/slides/kwkni-scala-best-compiling-ever/


打ち上げの飲み会でもコンパイル時間をどう楽しむかの話ばっかりしてた気がする。



wrote 2013/10/20 17:47:21

Kinect関連のメモ


下記を参考に、Unityでトラッキングさせる。

http://hameds3d.blogspot.jp/2012/01/how-to-setup-zigfu-and-unity3d-tutorial.html



さて。

普通にサンプルが動いたので、ポーズ認識までやろう。

10stock


・ポーズの入力再現を行う

AvatarFrontfacing ていうサンプルで、摘出できた。

こいつを基礎に、入力されるパラメータと連動する動きの入力値を得て、

って思ったんだけど、これポーズディテクターをなんとかして実装しないと行けないな。



・特定のポーズに対して動作するようにする


・認識部分を取り出す

・できれば依存を消す(何してるか解れば消せると思うが。


Windowsで準備

この辺がストレートに参考になる感じ。

http://unitygeek.hatenablog.com/entry/2012/09/03/194047


http://www.microsoft.com/en-us/kinectforwindowsdev/Start.aspx



気になる。

http://kinectrecognizer.codeplex.com



巡り巡って、OpenNIか、LibFreeNectを使うのが良さそうだ。

https://github.com/OpenKinect/libfreenect


libfreenect

インターフェースがあるよ的な話してるけど、とりあえずインプットだけを支えられれば良いので、

じゃあどうやってインプットぶち込むの?っていう方法を探す。

座標データとかがドカッとくるんだろうか。



OpenNI

ここを参考に粘り中。

http://blog.totakke.net/kinect/openni-mac-kinect.html

wrote 2013/10/05 19:39:15

nsws : command line WebSocket client. 


概要

標準入力をそのままWebScoketで流す

WebSocket Clientを作った。


nsws

https://github.com/sassembla/nsws


goで書いたのもあって、後でぎっはぶに上げる。


動機

テストから特定のWebSocketサーバに対して、

シーケンスのある内容を一定のタイミングで送り出すツールがほしかった。

いちいち繋ぎ直すのもアレだし、一度繋いで適当な動作、というのが希望。

また、stdinを受ける事でタイミングの問題解決位置を外部からの入力にずらしたい。

(こうすると外部から一斉に複数のWebSocketClientの入力をコントロールできる。)



使い方

標準入力を受けて射出。

tail -f something.txt | nsws -t ws://127.0.0.1:8823


tailで送ってきた内容をlocalのport8823へと回す。


メッセージを直打ちで流して終了

nsws -t ws://127.0.0.1:8823 -m "here comes daredevil !!"



欲しいなーって思うもの & 欲しいって言われたもの

・identityを表明するしかけ

(ゲームサーバ側から無視されてもいいんだけど、どこのどれが誰なのか、みたいな情報を接続時に送りたいなーっていうのがある。)


・フィルタリング


・header/footer(これはmessageに直接入れる方が筋がいいのでは



wrote 2013/10/03 9:00:45

sshでサーバに入ってtail結果をstdoutでローカルに流すツール作った


概要

内容はタイトルのごとく。


EnteringOrbit

https://github.com/sassembla/EnteringOrbit


用途は、


サーバ上で動いてるappのlogから、エラー情報や使用経路をリアルタイムにエディタに流す

というもの。



手順

次の手順を自動的に実行する。


sshで特定のサーバに入って、

特定のファイルをtail、

その内容をlocalのoutputとして、 標準出力 / WebSocket / ほか でpubsubできる感じにする。


サーバでのログをSublimeTextで開いたコードに反映させるのに使っている感じ

続く



wrote 2013/10/01 2:00:59

expect + ssh + tail で嵌った話


概要

expect を人から薦めてもらう機会があったので、やりたいこと一つ叶えてみてた。


sshでサーバに入って特定の語句を捉えてなんかする、、的なことが出来るので、

sshで入ってtailしたサーバのファイル更新内容をローカルへの標準入力に吐き出すみたいなのを作った。

EnteringOrbit

https://github.com/sassembla/EnteringOrbit/tree/master



困った事

expectでのssh後に素直にexpectでいろんなトラブルを待って、解消したらあきらめるとかtailするとかで良いと思ってたんだけど、

expect + ssh + tail なのがどうも良く無い。

予定だと、sshでログイン後に実行するのがtailで、これは本来は勝手には終了しないはずなのに、

expectコマンドで使うとtailでロックせずすっぽ抜けて、expectそのものが終了してしまう。


→(本来なら、tailは成立した瞬間からファイルの更新シグナルを待ち構える)


で、すっぽ抜けるので、どうしようかなーと思っていた。

なんとかなって、

結論としてはinteractで、expectで待ってくれないコマンドでもロックを効かせることができる。


下記のコマンドでOKだった。


expect -c "

spawn ssh someone@somewhere;

send \"tail -f ./some.txt \";

interact"



これで、ちゃんとtailが実行され続ける。


代償として、擬似的になんらかの入力を行わないと、Terminalにsshプロセスの残骸が残ったりするようだった。

アプリケーション側ではfileのcloseを入力する事でちゃんと閉じるようにしてある。



(メモ)README.mdに書くべき事

EnteringOrbit -s someone@somewhere -t ./some.txt | nnotif

で、サーバにsshで入ってsome.txtをtailした結果をMacのローカルなNotificationに放流できたりする。


これでサーバのログを見ながらコード上にエラー表示したりするのが楽になる。みたいな。


nnotif は標準入力からMacのNSDistributedNotificationを発行するやつ。


nnotif

https://github.com/sassembla/nnotif



やー やっぱりコマンドラインは柔軟だけど面倒くさいですね。あとでラップしちゃうからいいけど。



wrote 2013/09/29 1:21:08

MacNotifierを使ってデバッグとか動作確認とか


概要

21世紀にもなってアプリから.shを動かす部分のコード書いてるんだけど

デバッグが面倒くさい。

ので、Notificationを使うようにしたら捗ったよという話。

スクリーンショット 2013-09-13 20.44.29.png



Shellデバッグの問題点

shellのデバッグが面倒でつらい。


echoとかで頑張る?

App > .sh起動 > 出力はApp内のパイプ、、とかになっちゃうので。

色々みづらい。


ファイルとかに書き込む?

それも面倒だ。



それら以外の方法で、ある行を通過したらその旨を表示したいなーと考えてたら、

こんなの作ったのを思い出した。


MacNotifier

https://github.com/sassembla/SublimeSocket3/tree/master/tool/notification


コレを使うと、


open -a MacNotifier.app --args -t title -m message


で、

スクリーンショット 2013-09-13 20.38.42.png

みたいなMacの通知が表示できる。


Ruby版で先駆者が居て、bundle入れるのが面倒だったので独自にapp化した。

これを、「どこまで通ったか」に使えば良いんだ!!

というだけの話。



ファイル吐き出しができない環境、ログが見にくい環境で大助かり!全国から喜びの声が

以上

wrote 2013/09/13 9:27:52

Sherr アップデート


概要

Macで使える、*.shを放り込むとダブルクリックで使えるようになるアプリ

Sherr.app を私利私欲に基づいてアップデートした。

https://github.com/sassembla/Sherr

いちいちnodeとかshellをコマンドラインから叩いたりとかしてるひとにオススメ。


定期実行とかも可能になった。



機能追加一覧


1.放り込むshellに絶対パスでいろいろ書かないと動かないクソ仕様だった

放り込んだ*.shを、Sherr.appが置いてあるパスで叩いたのと同じ挙動になるように変更。

shellからの呼び出し先指定を気にしないでよくなった。



2.再帰的なshellの呼び出しを行えるようにした

shellを実行するためのマイクロサーバっぽくなった。


Sherr.app起動中、Sherr.appの中のcontinue.shを外部のshellとかから呼ぶことで、

Sherr.appをもう一度叩いた事になるようにした。つまりいくらでもいつでもネストできる。

sh ./Sherr.app/Contents/Resources/continue.sh


たとえば100回実行したい処理があったとして、

ファイルに回数を記録していって、それが100にとどくまで


処理 > カウントアップ > continue.shを呼ぶ


と繰り返えさせる事で、えらい速さで動く。

権限がappに準ずるので、ほとんどユーザー動作として動く感じ。


具体霊

100回ベンチを計りたい処理があったとして、

下記のようなshellを書いて、Sherr.appに喰わせると、高速に100回動いてとまる。

sample100.sh

filename=./record.txt

maxCount=100


if [ -f "${filename}" ]; then

echo "continue."

else

echo "generate file."

touch ${filename}

fi



# The behaviour what you want to benchmark

pwd


# get elapsed time & note it.

passedTime="だが断る"


echo $passedTime >> ${filename}




# count record-line num.

countbase=$(wc -l ${filename})



# trim filename with space.

count=${countbase% *}


if [ ${count} -lt ${maxCount} ]; then

# run next soon. add Token if need.

sh ./Sherr.app/Contents/Resources/continue.sh

fi


で、下記のような嫌がらせみたいなファイルが出来上がっていればOK

record.txt

スクリーンショット 2013-09-13 1.53.18.png

wrote 2013/09/13 1:33:09

Jenkins氏を優しくn回連続で走らせるシェル書いた


概要

Macなローカル環境で、Jenkinsさんを使ってベンチを取ろう!みたいな話があって、


・gitにcommitするたびにJenkins氏が目覚めた心で走り出す

・一回走るごとにどこかに速度を書き込む

・commitにつき100回連続で走ってほしい


というのがあり、なんかRemoteAPIとか組み合わせたら行けそうな気がして書いた。

プラグイン足すのも面倒で、、はい、、


そんな残念な脳みその結晶がこれです


L00p.sh

https://github.com/sassembla/l00p




使い方

プロジェクトにL00p.shを含み、shellとして実行すると、そのbuildから数えてn回連続で動く。


sh l00p.sh count.txt http://SOMEWHERE_MR_JENKINS_LIVES/Job/JOBNAME/build 100


これで、100回連続で、JOBNAMEというjobが走る。

並列でもないしJobの終了も待てるし中断もラクちん。



内容

第一引数の名前のファイルを作って、そこに何かを一回につき一行書き込む事で

回数の制御とデータ集めを行っている。


あ、たぶんMacのbashでしか動かない。

サーバ上で速度ベンチするわけじゃないので。


何に使っているの

こないだ作ったMac版S2のベンチ計測に使っています。

wrote 2013/09/09 21:35:36

brewKinect On Mac 環境を整える


概要

Macで、homebrewを使ってKinect環境を整えてみる。

Portsを使ったサンプルはいっぱいあるのでPortsのひとは回れ右すれば良いと思う。


あくまで単純にKinectをMacから動かそう的な奴なので、

その先の用途(Unity用のゲームとしてポーズとって何かの入力に使うとか)はココから先の話。



インストール


1.libusbをbrewから入れる

brew install libusb --universal


make部分でエラーがでるのは、/usr/local/includeへの書き込みを行おうとするため。

includeフォルダへの搔き込み権限不足でエラー出した。

brewsudo使わないので、該当のフォルダの権限を変更してからinstall実行すると良いと思う。



2.LibFreeNectをgit clone

https://github.com/OpenKinect/libfreenect



3.cmakeを入れる

LibFreeNectをビルドするために使う。

MacOSX 用のはここから手に入る。

http://www.cmake.org


自分はCMake 2.8-10で試した。



4.ビルド

LibFreeNectをビルドする。

libFreeNectの入っているフォルダまで行き、


cmake .


エラーが出る場合、libusbがちゃんと入ってない(libusbの時点でerrorが出てるとか)だと思う。


続けてmake

highvision:libfreenect highvision$ make


で、


Scanning dependencies of target freenect

[  4%] Building C object src/CMakeFiles/freenect.dir/core.c.o

[  8%] Building C object src/CMakeFiles/freenect.dir/tilt.c.o

(中略)

[100%] Building CXX object wrappers/cpp/CMakeFiles/cppview.dir/cppview.cpp.o

Linking CXX executable ../../bin/cppview

[100%] Built target cppview



からの、install

sudo make install


LibFreeNectが無事に入った。


5.試運転

ココまで来たら、KinectをUSBでMacに繋いで、下記から適当に選んで実行するとKinectを自由に動かせる。

glpclview

立体分割(大体この辺の奥行きにあるんじゃねーかなーってところを計算してポリゴンに貼ったみたいに見せる)


Preferencesからトラックパッドでのコントロールとかが可能になるので、

画面サイズ変えつつDrag&Dropとかやってると結構楽しめると思う。

wでズームイン、sでズームアウトが出来る。


glview

標準的な2カメラでの深度色付け表示

hiview

カメラ一つずつを分けて表示


regview

被写界深度付きビューが見れる


tiltdemo

ひたすらKinectの角度が変わる


wavrecord

自分の環境だと入ってないよ! て言われた。

micview

自分の環境だと入ってないよ! て言われた。


regtest

自分の環境だと入ってないよ! て言われた。



参考

10,8対応

http://www.codingcolor.com/featured-articles/set-up-kinect-on-osx-10-8-mountain-lion/

記事はportだけど、brewからで同様の手順でできた。

wrote 2013/09/08 13:06:04

LLVM3.3 on Mac


概要

なんかMacでLLVM動かすの詰まるケースがあった、、というのを聞いて、

最新Macだとそうなのか?よくわからんけど原因切り分けのために試してみる。



DL

http://llvm.org/releases/download.html#3.3

から、


llvm-3.3.src.tar

cfe-3.3.src.tar

clang-tools-extra-3.3.src.tar


などを落とし、



llvmのフォルダのtools以下に、各フォルダ名を書き換えて入れる

cfe* -> /tools/clang

clang-tools-extra* -> /tools/clang/tools/extra


で、llvmのソースがあるフォルダで、

./configure

make

make install


でゲームエンド。

makeで時間かかるけど、終了した時点で、

Release+Asserts フォルダにbinとかが出来てる筈。




wrote 2013/09/03 15:40:01

SublimeSocketAsset 1.6.7出てた


概要

コレ

http://u3d.as/content/sassembla/sublime-socket-asset/4SP


なんか出し直して3日くらいで承認通ってたらしい。。。えーメールもらってないけど、、

まあーーいいか!!

それはそれで問いつめるとして。


Sublime Text シリーズでUnityのライブ補完が効くよ!!

wrote 2013/08/20 7:34:40

SublimeSocketAssetに補完機能つけた


概要

Sublime Textを使ってUnityのコードを書いていたのだけれど、


Sublime Text用に用意されていたUnityのス二ペットが不正確や不足で不満だった。


また、補完機構のプラグインも有ったのだけれど、

中身がexeでWin向けだけ & 自分の作った部分の補完とかの設定が面倒だった。


ので、

SublimeSocketAssetに機能追加する形で実装した。


現行verの1.5.2ではなく、申請済みの1.6.xから動作するようになる。

なんとなく、今のうちに買っておく事をオススメする。


Unityの基底クラスや、SystemなどのC#関連、自分の書いたコードや、

プロジェクト中で使っている他のAssetの情報も含めて補完している。


ヒャッホーゥゥゥ!! 快適快適!!


Win版

https://vimeo.com/71184393



Mac版

https://vimeo.com/71184153



補完開始から終了まで非同期で動くので、ユーザー操作を全くロックせず補完が出せる。 

補完速度もそれなりに速い、はず。 最大量でも0.3秒くらい。

全盛期のころのEcliなんとかを凌駕したかった。


そしてなによりSublime Textのファジィーな入力候補選定が使い放題なので(ry


日に日に「あ、あれなんてクラスだったっけ、、T、、Tが2個くらい入ってた気がする、、」とか

使う側の残念さが仕上がっていく。 俺はもう駄目だ。



補完候補の絞り込みとかはそれなりに頑張って作らないと不愉快な感じだったので、頑張ってみた。

なんというか修正やメンテも含めて、改善しやすい感じに出来たと思う。



仕組み

Unityが吐き出したdllを解析している。


候補選定はScalaコンパイラ用に別口で作った機構を流用できたので、楽勝だぜーと思っていたのだが、

言語やUnityのコンパイラとしての前提、静的解析できる機構の有無があり、結局似ても似つかなくなった。


大きく役割分担を分けて書くと、


Sublime Text側

Sublime Text : View

SublimeSocket : 接続機構、viewデータ送付、補完候補の受信、STのAPI実行


Unity側

SublimeSocketAsset : viewデータ解析、dll解析、補完候補選定、SublimeSocketへと送付

Unity : 動作環境


という感じになっている。



内輪話になるけど、Unityの「コンパイルする際には全Assetもリロードされる」という仕様と

補完情報の持ち方の兼ね合いが、作っていてとても面白かった。


必ず

・Unityが全てをコンパイル

・コンパイル完了後にEditor系のAssetが起動

・ゲームのコードが~

みたいな挙動順になる。

で、出来るだけ速くコンパイル後の補完準備が完了するように、並列でいろいろ処理してみた。


完全に変化しないSystem系やUnity系のライブラリが膨大で、これをマトモにコンパイル後に展開すると

平気で4秒とかかかるので却下しつつ、キャッシュ作ったり、圧縮したりして高速化。


最終的には、コンパイル後の静的解析が1.7秒、並行で走るキャッシュ展開が1.8秒、なので

保存から1.8秒くらいで全ての用意ができる。



Unityのプラグインは並列動作みたいなのができないと思っていたんだけど、 WebSocketの受信からだと並行し放題みたいだ。


ただ暗黙のタイムアウトみたいなのがあって、10秒?以上走るような重いものを動かすと、

いつのまにかやめてるような気がした。ポーリングやSignalPingPongみたいなのは止めておいた方が平和そう。



現状

Mac,Win向けに調整が終わって、土曜に申請済み。

さてはて。



これから

補完機構を作っていて、どうも、コードブロックごとの時間表時などがリアルタイムで

出来そうなので、気が向いたら作る。


Unityみたいなゲームで使うのだと、なかなか嬉しい。


あとやっぱりSTに自由描画レイヤーが欲しい。png貼らせてくんないかなー。

そしたらLLVMでの解析とかunreachableBlockとかが図示できる。



wrote 2013/07/28 16:12:53

Sublime Textの補完機構の詳細の概略


概要

Sublime Text シリーズで、補完を出すAPIについて調べるチャンスがあったので、

纏めておく。



Sublime Textにおける補完とは

こんな感じの見た目で出る、補完お助け機能みたいなの。

左がメソッドとかクラス名とか。右が返りの型、に”してみた”。

スクリーンショット 2013-07-17 10.54.12.png

エディタに出てるとこだとこんなの。

スクリーンショット 2013-07-17 10.55.40.png


入力選択はSublimeお得意のファジーさを発揮し、補完開始すると、

tabキーでのパラメータ入力移動とかがある。

スクリーンショット 2013-07-17 10.56.54.png

EclipseとかIDEのアレと一緒。



API

ドキュメントに無い(殺)APIを使う。

def on_query_completions(self, view, prefix, locations):


なんで無いのかForumで問いただして見ているところ。



動作内容

候補のフォーマットがわからん。で、調べたところ、最終的に

https://gist.github.com/agibsonsw/2030626

あたりが参考になった。

このAPIは、

・特定の形式の(str,str)のtupleが入ったlistをこのAPIのオーバーライドをしたメソッドから返すようにすると、それらを補完候補として出す

・view.run_command("auto_complete") で任意のタイミングで呼び出せる

・view.run_command("hide_auto_complete") で任意のタイミングで消せる

という特性がある。


補完候補に出てさえしまえば、あとはSublimeお得意のファジィーなマッチがエクセレントするので、ラク。


っていうかドキュメントォォォォ



このAPIの使い方

他のハンドラAPIと同様、overrideする。


class CaptureEditing(sublime_plugin.EventListener):

def on_query_completions(self, view, prefix, locations):

return [("compile compile fn", "compile(${1:source}, ${2:filename}, ${3:mode}${4:[, flags]}${5:[, dont_inherit]})$0")]


書式

このAPIから下記のようなlistデータを返すと補完ウインドウが出る。


[("compile compile fn", "compile(${1:source}, ${2:filename}, ${3:mode}${4:[, flags]}${5:[, dont_inherit]})$0")]


で、候補として表示される内容は

compile[タブ]compile fn

になる。


この補完を選択後にコードに入力されるデータは下記になる。

compile(source, filename, mode[, flags][, dont_inherit])

()の中身はtabで右に移動、space+tabで左に移動できる。

= $マーク+数字で、tabキーでの移動候補になっている、と考えるとしっくりくる。



詳細

listの中の各要素が補完候補になっている。

文字列のtupleになっていて、


("compile compile fn", "compile(${1:source}, ${2:filename}, ${3:mode}${4:[, flags]}${5:[, dont_inherit]})$0")


の最初の値

"compile compile fn"


は、補完の説明文になっている。

返り値、メソッド名とかがいい感じ。

tabで区切ると左端、右端にそれぞれが表示される。


次の値は、

"compile(${1:source}, ${2:filename}, ${3:mode}${4:[, flags]}${5:[, dont_inherit]})$0"


文字列()$0

この$0は、全体を入力し終わった際に、最後にtabキーで到達できる場所になっている。

${数字:パラメータ文字列} は、

$が内容を範囲で持つ場合、このパラメータ名を枠として、文字入力できる動作になる。

ちなみにパラメータ文字列部分を[, 文字列]にすることで、not needを表明できる、みたいなオプションもある。


overloadとかのときに使うと良い。



使い道

と、表示するための情報とかは楽に出せるんだけど、Sublime TextからこのAPIをちゃんと使うには、


・入力状況から特定のタイミングを検知するようにイベントトリガーを設置する

・トリガーが正しいかどうか入力中バッファの状況を見て判断する

・データを読んで、補完内容を選出する

・補完内容を配列として返す


というシークエンスが必要で、コレを全部プラグイン内で実行しないといけなくて大変。

コンパイルの結果を流用できるような規模でないと、とても作れないと思う。



簡単なまとめまでに。

wrote 2013/07/17 10:13:36

Windows7、8でUnity連携


概要

制作、販売しているUnityのAssetで、Windowsにも対応しよう、みたいな事をしていた。


具体的には、

・AssetとUnity以外を特別にインストールしない前提で

・Unityと連携して、特定のタイミングでUnityのビルドを走らせる

・メッセージを表示する

ということがしたかった。

需要が無いと思っていたし、勝手も解らなかったので、

Windows用にはそのへん用意するつもりが無かったんだが、

使ってみるとUnityにビルドさせる機構は必須だみたいな話もらったので、はい。

作る。



Unityと連携して、特定のタイミングでUnityのビルドを走らせる

UnityにそんなAPIは無い。


で、Mac側でも使った手として、アプリケーションがアクティブになるとコンパイルが走る、という特性を悪用する。


APIがあればぜひそれを使うべきだと思っているが、無い上に有用なのでしょうがない。

どのくらい有用かはこの辺を見てほしい。



WIndows用のexeで、フォーカス変更するのを作る

下記メソッドでWindowへとフォーカスを与えることが出来た。


IntPtr hWnd = FindWindow(null, windowTitle);

if (hWnd != IntPtr.Zero)

{

    SetForegroundWindow(hWnd);

}


で、上記のwindowTitleをどうしようかと。

WindowsのアプリケーションごとのWindow名ってものすごい状態なのな。

プロセス名なら画一的な内容になるので、プロセス名をキーに、そのプロセスが所持している

Windowの名称を取得するようにして、無事動作した。


最終的にコマンドラインアプリケーションにできた。

SwitchApp.exe -f app_process_name -t app_process_name

アプリケーションの種類をWindowsApplicationに設定する事で、このSwitchApp自体はWindow無しで動作する。


from と to の間隔が短すぎると、Unityのビルドが始まらないことが多々あった。このへんMacとは違う。

Sleepをいれて、、、場当たり的に、、、こう、、


ただどーーーもSleepはやっぱり駄目みたいで、動いたり動かなかったりする。

このへんは暫定的に別の方法で解消した。


リポジトリ

https://github.com/sassembla/WinSwitchApp


メッセージを表示する

MacだとNotificationCenterとか、Growlとか通知系がけっこうあったので、

似たようなものを使いたく。



Win8でのToast

7ではそういうのは無い、、と思う。無理してつけてもなーもう時代おくr

で、このへんもアプリケーションにして出すと思う。


wrote 2013/07/04 15:29:15

apportableについて


概要

調べ中なので、この文章は、知ってる人が見ればいいや程度のもので、啓蒙、オススメなどをするものでは有りません。


いろいろあってIndieを触ってみる事になった。

http://www.apportable.com

まだ色々整ってない印象。



最初に注意

apportableのインストール前に、XcodeのDeveloperPreviewとかが手元に有る場合、

注意。

apportableのツール内からxcrunで使われるんだけど、

プレビュー版が自動的に使われてそりゃもう動かんかった。

xcode-select --switch で指定し直せば動く。



導入

ログイン後、ページからStarterKitがゲットできる。

ここには書かないのでえーと頑張ってアカウント作ってください。


ゴバっといろいろインストールします。

インストール先は限定されているので、安心。


highvision:~ highvision$ XXXXXXXXXXXXXXXXXXXXXXXXX

  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current

                                 Dload  Upload   Total   Spent    Left  Speed

100  1345  100  1345    0     0    544      0  0:00:02  0:00:02 --:--:--   928

Checking for latest SDK...

Downloading SDK from XXXXXXXXXXXXXXXXXXXXXXXXX

  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current

                                 Dload  Upload   Total   Spent    Left  Speed

100 47.4M  100 47.4M    0     0   596k      0  0:01:21  0:01:21 --:--:--  505k

SDK installed into /Users/highvision/.apportable/SDK. Now updating toolchain.

vorbis-tools

==============================

installed: 0c2e4c653c107b53e366ad8d352839dfca8495b0

current: 0c2e4c653c107b53e366ad8d352839dfca8495b0

stable:  0c2e4c653c107b53e366ad8d352839dfca8495b0

1) 0c2e4c653c107b53e366ad8d352839dfca8495b0 Tue May 21 10:26:49 2013



android-ndk

==============================

installed: r8d.1

current: r8d.1

stable:  r8d.1

1) r8d Sat Feb 23 19:47:47 2013

2) r8d.1 Wed May 8 00:38:36 2013



clang

==============================

installed: 7fc8b05e4f57f61dbbbe5c8e62581b0e0c42941e

current: 7fc8b05e4f57f61dbbbe5c8e62581b0e0c42941e

stable:  7fc8b05e4f57f61dbbbe5c8e62581b0e0c42941e

1) 06017c71300e33419f46b46f350192b6032e7e0d Sat Feb 23 19:47:47 2013

2) c250d8b6c0aba5ae481526606084bb3112c3e6ff Tue Feb 26 20:37:09 2013

3) bee9c1e91260dd269d1a85ec5d11f1e8835c25b2 Tue Feb 26 20:37:09 2013

4) 925804cd386ea8c186ee9c6995cd44bab3b95f14 Sun May 5 17:28:19 2013

5) 7fc8b05e4f57f61dbbbe5c8e62581b0e0c42941e Thu May 23 23:41:34 2013 llvm/clang 3.3



profiler

==============================

installed: c905419b4766ef76d2eab8d17e98ee185f7e911c

current: c905419b4766ef76d2eab8d17e98ee185f7e911c

stable:  c905419b4766ef76d2eab8d17e98ee185f7e911c

1) c905419b4766ef76d2eab8d17e98ee185f7e911c Tue Jun 4 13:08:24 2013 1.01



m4

==============================

installed: e447db581a4b3d4655ad62ea85d0445342c4ac6a

current: e447db581a4b3d4655ad62ea85d0445342c4ac6a

stable:  e447db581a4b3d4655ad62ea85d0445342c4ac6a

1) e447db581a4b3d4655ad62ea85d0445342c4ac6a Mon Jun 3 19:13:45 2013



gdb

==============================

installed: 8c0d2ad999905881f5d1b9dbbb8169f3a56a7171

current: ff0611b8b721b3bf393c655c7d147de52cc850ac

stable:  4e639d65677bb04a16bd74a6ceb923855ac81c97

1) ee42cf949ec7ce4e3cf2ab0405fd394f29b27e40 Sat Feb 23 19:47:47 2013

2) fcb36ce2778272469bf28e91280e81838c8373de Sat Feb 23 19:47:47 2013

3) 6675c30e360ae2abc7b96c040c3867a37ae0440a Wed Apr  3 16:33:17 2013

4) a0aeb55ac44b11b83707fedf19bac41b616948c0 Sun May 5 17:28:19 2013

5) 8c0d2ad999905881f5d1b9dbbb8169f3a56a7171 Wed May 29 17:28:19 2013

6) 4e639d65677bb04a16bd74a6ceb923855ac81c97 Thu May 30 17:49:10 2013

7) ff0611b8b721b3bf393c655c7d147de52cc850ac Thu Jun 27 14:58:40 2013

  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current

                                 Dload  Upload   Total   Spent    Left  Speed

100  9.9M  100  9.9M    0     0   530k      0  0:00:19  0:00:19 --:--:--  657k

x gdb/

x gdb/bin/

x gdb/include/

x gdb/lib/

x gdb/share/

x gdb/share/gdb/

x gdb/share/info/

x gdb/share/locale/

x gdb/share/man/

x gdb/share/remote/

x gdb/share/remote/android/

x gdb/share/remote/android/arm/

x gdb/share/remote/android/arm/gdbserver

x gdb/share/man/man1/

x gdb/share/man/man1/arm-elf-linux-gdb.1

x gdb/share/man/man1/arm-elf-linux-run.1

x gdb/share/locale/da/

x gdb/share/locale/de/

x gdb/share/locale/es/

x gdb/share/locale/fi/

x gdb/share/locale/fr/

x gdb/share/locale/ga/

x gdb/share/locale/id/

x gdb/share/locale/it/

x gdb/share/locale/ja/

x gdb/share/locale/nl/

x gdb/share/locale/pt_BR/

x gdb/share/locale/ro/

x gdb/share/locale/ru/

x gdb/share/locale/rw/

x gdb/share/locale/sv/

x gdb/share/locale/tr/

x gdb/share/locale/uk/

x gdb/share/locale/vi/

x gdb/share/locale/zh_CN/

x gdb/share/locale/zh_CN/LC_MESSAGES/

x gdb/share/locale/zh_CN/LC_MESSAGES/bfd.mo

x gdb/share/locale/zh_CN/LC_MESSAGES/opcodes.mo

x gdb/share/locale/vi/LC_MESSAGES/

x gdb/share/locale/vi/LC_MESSAGES/bfd.mo

x gdb/share/locale/vi/LC_MESSAGES/opcodes.mo

x gdb/share/locale/uk/LC_MESSAGES/

x gdb/share/locale/uk/LC_MESSAGES/bfd.mo

x gdb/share/locale/tr/LC_MESSAGES/

x gdb/share/locale/tr/LC_MESSAGES/bfd.mo

x gdb/share/locale/tr/LC_MESSAGES/opcodes.mo

x gdb/share/locale/sv/LC_MESSAGES/

x gdb/share/locale/sv/LC_MESSAGES/bfd.mo

x gdb/share/locale/sv/LC_MESSAGES/opcodes.mo

x gdb/share/locale/rw/LC_MESSAGES/

x gdb/share/locale/rw/LC_MESSAGES/bfd.mo

x gdb/share/locale/ru/LC_MESSAGES/

x gdb/share/locale/ru/LC_MESSAGES/bfd.mo

x gdb/share/locale/ro/LC_MESSAGES/

x gdb/share/locale/ro/LC_MESSAGES/bfd.mo

x gdb/share/locale/ro/LC_MESSAGES/opcodes.mo

x gdb/share/locale/pt_BR/LC_MESSAGES/

x gdb/share/locale/pt_BR/LC_MESSAGES/opcodes.mo

x gdb/share/locale/nl/LC_MESSAGES/

x gdb/share/locale/nl/LC_MESSAGES/opcodes.mo

x gdb/share/locale/ja/LC_MESSAGES/

x gdb/share/locale/ja/LC_MESSAGES/bfd.mo

x gdb/share/locale/it/LC_MESSAGES/

x gdb/share/locale/it/LC_MESSAGES/opcodes.mo

x gdb/share/locale/id/LC_MESSAGES/

x gdb/share/locale/id/LC_MESSAGES/bfd.mo

x gdb/share/locale/id/LC_MESSAGES/opcodes.mo

x gdb/share/locale/ga/LC_MESSAGES/

x gdb/share/locale/ga/LC_MESSAGES/opcodes.mo

x gdb/share/locale/fr/LC_MESSAGES/

x gdb/share/locale/fr/LC_MESSAGES/bfd.mo

x gdb/share/locale/fr/LC_MESSAGES/opcodes.mo

x gdb/share/locale/fi/LC_MESSAGES/

x gdb/share/locale/fi/LC_MESSAGES/bfd.mo

x gdb/share/locale/fi/LC_MESSAGES/opcodes.mo

x gdb/share/locale/es/LC_MESSAGES/

x gdb/share/locale/es/LC_MESSAGES/bfd.mo

x gdb/share/locale/es/LC_MESSAGES/opcodes.mo

x gdb/share/locale/de/LC_MESSAGES/

x gdb/share/locale/de/LC_MESSAGES/opcodes.mo

x gdb/share/locale/da/LC_MESSAGES/

x gdb/share/locale/da/LC_MESSAGES/bfd.mo

x gdb/share/locale/da/LC_MESSAGES/opcodes.mo

x gdb/share/info/annotate.info

x gdb/share/info/bfd.info

x gdb/share/info/configure.info

x gdb/share/info/dir

x gdb/share/info/gdb.info

x gdb/share/info/gdbint.info

x gdb/share/info/stabs.info

x gdb/share/info/standards.info

x gdb/share/gdb/python/

x gdb/share/gdb/syscalls/

x gdb/share/gdb/syscalls/amd64-linux.xml

x gdb/share/gdb/syscalls/gdb-syscalls.dtd

x gdb/share/gdb/syscalls/i386-linux.xml

x gdb/share/gdb/syscalls/mips-n32-linux.xml

x gdb/share/gdb/syscalls/mips-n64-linux.xml

x gdb/share/gdb/syscalls/mips-o32-linux.xml

x gdb/share/gdb/syscalls/ppc-linux.xml

x gdb/share/gdb/syscalls/ppc64-linux.xml

x gdb/share/gdb/syscalls/sparc-linux.xml

x gdb/share/gdb/syscalls/sparc64-linux.xml

x gdb/share/gdb/python/gdb/

x gdb/share/gdb/python/gdb/__init__.py

x gdb/share/gdb/python/gdb/command/

x gdb/share/gdb/python/gdb/printing.py

x gdb/share/gdb/python/gdb/prompt.py

x gdb/share/gdb/python/gdb/types.py

x gdb/share/gdb/python/gdb/command/__init__.py

x gdb/share/gdb/python/gdb/command/explore.py

x gdb/share/gdb/python/gdb/command/pretty_printers.py

x gdb/share/gdb/python/gdb/command/prompt.py

x gdb/lib/libarm-elf-linux-sim.a

x gdb/lib/x86_64/

x gdb/lib/x86_64/libiberty.a

x gdb/include/gdb/

x gdb/include/gdb/jit-reader.h

x gdb/bin/arm-elf-linux-gdb

x gdb/bin/arm-elf-linux-run



adb

==============================

installed: cd96bfaea0f38a2de67e478463b24a4394be2cb3

current: cd96bfaea0f38a2de67e478463b24a4394be2cb3

stable:  cd96bfaea0f38a2de67e478463b24a4394be2cb3

1) cd96bfaea0f38a2de67e478463b24a4394be2cb3 Wed Jun 12 23:28:06 2013



android-sdk

==============================

installed: r21.0.1.1

current: r21.0.1.1

stable:  r21.0.1.1

1) r21.0.1 Sat Feb 23 19:47:47 2013

2) r21.0.1.1 Wed May 8 00:38:36 2013



Toolchain downloaded into /Users/highvision/.apportable/toolchain.

Apportable CLI is successfully installed at /Users/highvision/.apportable/SDK/bin/apportable

If you're using the default shell, add the Apportable CLI to your PATH using:

(echo; echo 'PATH="/Users/highvision/.apportable/SDK/bin:$PATH"') >> ~/.bash_profile; source ~/.bash_profile

highvision:~ highvision$ /Users/highvision/.apportable/SDK/bin/apportable update

  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current

                                 Dload  Upload   Total   Spent    Left  Speed

100  1345    0  1345    0     0    428      0 --:--:--  0:00:03 --:--:--   848

Checking for latest SDK...

Downloading SDK from XXXXXXXXXXXXXXXXXXXXXXXXX

  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current

                                 Dload  Upload   Total   Spent    Left  Speed

100 47.4M  100 47.4M    0     0   514k      0  0:01:34  0:01:34 --:--:--  684k

SDK installed into /Users/highvision/.apportable/SDK. Now updating toolchain.

vorbis-tools

==============================

installed: 0c2e4c653c107b53e366ad8d352839dfca8495b0

current: 0c2e4c653c107b53e366ad8d352839dfca8495b0

stable:  0c2e4c653c107b53e366ad8d352839dfca8495b0

1) 0c2e4c653c107b53e366ad8d352839dfca8495b0 Tue May 21 10:26:49 2013



android-ndk

==============================

installed: r8d.1

current: r8d.1

stable:  r8d.1

1) r8d Sat Feb 23 19:47:47 2013

2) r8d.1 Wed May 8 00:38:36 2013



clang

==============================

installed: 7fc8b05e4f57f61dbbbe5c8e62581b0e0c42941e

current: 7fc8b05e4f57f61dbbbe5c8e62581b0e0c42941e

stable:  7fc8b05e4f57f61dbbbe5c8e62581b0e0c42941e

1) 06017c71300e33419f46b46f350192b6032e7e0d Sat Feb 23 19:47:47 2013

2) c250d8b6c0aba5ae481526606084bb3112c3e6ff Tue Feb 26 20:37:09 2013

3) bee9c1e91260dd269d1a85ec5d11f1e8835c25b2 Tue Feb 26 20:37:09 2013

4) 925804cd386ea8c186ee9c6995cd44bab3b95f14 Sun May 5 17:28:19 2013

5) 7fc8b05e4f57f61dbbbe5c8e62581b0e0c42941e Thu May 23 23:41:34 2013 llvm/clang 3.3



profiler

==============================

installed: c905419b4766ef76d2eab8d17e98ee185f7e911c

current: c905419b4766ef76d2eab8d17e98ee185f7e911c

stable:  c905419b4766ef76d2eab8d17e98ee185f7e911c

1) c905419b4766ef76d2eab8d17e98ee185f7e911c Tue Jun 4 13:08:24 2013 1.01



m4

==============================

installed: e447db581a4b3d4655ad62ea85d0445342c4ac6a

current: e447db581a4b3d4655ad62ea85d0445342c4ac6a

stable:  e447db581a4b3d4655ad62ea85d0445342c4ac6a

1) e447db581a4b3d4655ad62ea85d0445342c4ac6a Mon Jun 3 19:13:45 2013



gdb

==============================

installed: 4e639d65677bb04a16bd74a6ceb923855ac81c97

current: ff0611b8b721b3bf393c655c7d147de52cc850ac

stable:  4e639d65677bb04a16bd74a6ceb923855ac81c97

1) ee42cf949ec7ce4e3cf2ab0405fd394f29b27e40 Sat Feb 23 19:47:47 2013

2) fcb36ce2778272469bf28e91280e81838c8373de Sat Feb 23 19:47:47 2013

3) 6675c30e360ae2abc7b96c040c3867a37ae0440a Wed Apr  3 16:33:17 2013

4) a0aeb55ac44b11b83707fedf19bac41b616948c0 Sun May 5 17:28:19 2013

5) 8c0d2ad999905881f5d1b9dbbb8169f3a56a7171 Wed May 29 17:28:19 2013

6) 4e639d65677bb04a16bd74a6ceb923855ac81c97 Thu May 30 17:49:10 2013

7) ff0611b8b721b3bf393c655c7d147de52cc850ac Thu Jun 27 14:58:40 2013



adb

==============================

installed: cd96bfaea0f38a2de67e478463b24a4394be2cb3

current: cd96bfaea0f38a2de67e478463b24a4394be2cb3

stable:  cd96bfaea0f38a2de67e478463b24a4394be2cb3

1) cd96bfaea0f38a2de67e478463b24a4394be2cb3 Wed Jun 12 23:28:06 2013



android-sdk

==============================

installed: r21.0.1.1

current: r21.0.1.1

stable:  r21.0.1.1

1) r21.0.1 Sat Feb 23 19:47:47 2013

2) r21.0.1.1 Wed May 8 00:38:36 2013



Toolchain downloaded into /Users/highvision/.apportable/toolchain.

Apportable CLI is successfully installed at /Users/highvision/.apportable/SDK/bin/apportable

If you're using the default shell, add the Apportable CLI to your PATH using:

(echo; echo 'PATH="/Users/highvision/.apportable/SDK/bin:$PATH"') >> ~/.bash_profile; source ~/.bash_profile

highvision:~ highvision$ 




ここまでで、2.6Gくらい持っていく。


インストールは下記にされる

/Users/highvision/.apportable/SDK/bin あたり。

もさっと。

スクリーンショット 2013-07-02 15.34.01.png

Start

まずこのへん見ろってサイトにあったので見る

http://docs.apportable.com/sample-apps.html#tweejump


「もしAndroid触った事無くても大丈夫、iOS7とおなじようなもんです」っていきなり言っててワロタ。はい。


で、

https://github.com/haqu/tweejump

をDLしてやってみろksg、みたいな話。


PapiJumpのTwアイコン版です。うわあなつかしい。

そんなPapiJump

mzl.akpjwtuo.320x480-75.jpg



で、まず動かすのはiOS App


Xcodeプロジェクトを開いて、そのままiOSとかで実行すると

a.png

まーこんな感じで動作する。


Android App 化

事前に実機を繋いでおく必要がある。


Xcode プロジェクト フォルダがある場所で、

apportable load


で、またモサッと。


highvision:tweejump highvision$ /Users/highvision/.apportable/SDK/bin/apportable load

Building to /Users/highvision/.apportable/SDK/Build/android-armeabi-debug

Updating configuration parameters... Building Xcode project /Users/highvision/Desktop/tweejump/tweejump

Scanning build configuration for target tweejump

Merging configuration parameters.



It looks like you're compiling this app for the first time.

tweejump.approj/configuration.json will be created for you.

A few quick questions and you'll be on your way:


If the app is using OpenGL ES, does it use ES1 or ES2? (Cocos2D 1.X uses ES1, 2.X uses ES2)

[1/2] 


使ってない場合どうこたえろっちゅーねん → 何も打たずエンターでOK。


Should the app initially launch in landscape or portrait orientation? (default: landscape)

[L/p] 

どちらなりと。


Loading configuration.

Finished parsing configuration.

scons: Building targets ...

Compiling /Users/highvision/Desktop/tweejump/tweejump/AppDelegate.m

Compiling /Users/highvision/Desktop/tweejump/tweejump/Classes/Game.m

Compiling /Users/highvision/Desktop/tweejump/tweejump/Classes/Highscores.m

Compiling /Users/highvision/Desktop/tweejump/tweejump/Classes/Main.m

Compiling /Users/highvision/Desktop/tweejump/tweejump/RootViewController.m

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/FontLabel/FontLabel.m

/Users/highvision/Desktop/tweejump/tweejump/Classes/Game.m:266:7: warning: 

      expression result unused [-Wunused-value]

                for(t; t < kPlatformsStartTag + kNumPlatforms; t++) {

                    ^

/Users/highvision/Desktop/tweejump/tweejump/Classes/Game.m:296:7: warning: 

      expression result unused [-Wunused-value]

                for(t; t < kCloudsStartTag + kNumClouds; t++) {

                    ^

/Users/highvision/Desktop/tweejump/tweejump/Classes/Game.m:309:7: warning: 

      expression result unused [-Wunused-value]

                for(t; t < kPlatformsStartTag + kNumPlatforms; t++) {

                    ^

/Users/highvision/Desktop/tweejump/tweejump/Classes/Main.m:112:6: warning: 

      expression result unused [-Wunused-value]

        for(t; t < kCloudsStartTag + kNumClouds; t++) {

            ^

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/FontLabel/FontLabelStringDrawing.m

1 warning generated.

3 warnings generated.

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/FontLabel/FontManager.m

/Users/highvision/Desktop/tweejump/tweejump/libs/FontLabel/FontLabelStringDrawing.m:458:25: warning: 

      incompatible pointer types initializing 'NSMutableCharacterSet *' with an

      expression of type 'NSCharacterSet *' [-Wincompatible-pointer-types]

  ...*alphaCharset = [NSMutableCharacterSet alphanumericCharacterSet];

      ^              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/FontLabel/ZAttributedString.m

1 warning generated.

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/FontLabel/ZFont.m

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/CCAction.m

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/CCActionCamera.m

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/CCActionEase.m

/Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/CCAction.m:67:77: warning: 

      format specifies type 'unsigned int' but the argument has type

      'CCAction *' [-Wformat]

  ...stringWithFormat:@"<%@ = %08X | Tag = %i>", [self class], self, tag_];

                              ~~~~                             ^~~~

                              %8@

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/CCActionGrid.m

1 warning generated.

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/CCActionGrid3D.m

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/CCActionInstant.m

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/CCActionInterval.m

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/CCActionManager.m

/Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/CCActionInstant.m:260:4: warning: 

      format specifies type 'unsigned int' but the argument has type

      'CCCallFunc *' [-Wformat]

                        self,

                        ^~~~

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/CCActionPageTurn3D.m

1 warning generated.

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/CCActionProgressTimer.m

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/CCActionTiledGrid.m

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/CCActionTween.m

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/CCAnimation.m

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/CCAnimationCache.m

/Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/CCAnimation.m:73:88: warning: 

      format specifies type 'unsigned int' but the argument has type

      'CCAnimation *' [-Wformat]

  ...= %08X | frames=%d, delay:%f>", [self class], self,

       ~~~~                                        ^~~~

       %8@

1 warning generated.

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/CCAtlasNode.m

/Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/CCAnimationCache.m:70:92: warning: 

      format specifies type 'unsigned int' but the argument has type

      'CCAnimationCache *' [-Wformat]

  ...= %08X | num of animations =  %i>", [self class], self, [animations_ cou...

       ~~~~                                            ^~~~

       %8@

1 warning generated.

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/CCBlockSupport.m

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/CCCamera.m

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/CCConfiguration.m

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/CCDirector.m

/Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/CCCamera.m:46:94: warning: 

      format specifies type 'unsigned int' but the argument has type

      'CCCamera *' [-Wformat]

  ...= %08X | center = (%.2f,%.2f,%.2f)>", [self class], self, centerX_, cent...

       ~~~~                                              ^~~~

       %8@

1 warning generated.

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/CCDrawingPrimitives.m

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/CCGrabber.m

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/CCGrid.m

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/CCLabelAtlas.m

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/CCLabelBMFont.m

/Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/CCGrid.m:128:87: warning: 

      format specifies type 'unsigned int' but the argument has type

      'CCGridBase *' [-Wformat]

  ...= %08X | Dimensions = %ix%i>", [self class], self, gridSize_.x, gridSize...

       ~~~~                                       ^~~~

       %8@

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/CCLabelTTF.m

1 warning generated.

/Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/CCLabelBMFont.m:124:93: warning: 

      format specifies type 'unsigned int' but the argument has type

      'CCBMFontConfiguration *' [-Wformat]

  ...= %08X | Kernings:%d | Image = %@>", [self class], self,

       ~~~~                                             ^~~~

       %8@

/Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/CCLabelTTF.m:139:84: warning: 

      format specifies type 'unsigned int' but the argument has type

      'CCLabelTTF *' [-Wformat]

  ...stringWithFormat:@"<%@ = %08X | FontSize = %.1f>", [self class], self, f...

                              ~~~~                                    ^~~~

                              %8@

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/CCLayer.m

1 warning generated.

1 warning generated.

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/CCMenu.m

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/CCMenuItem.m

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/CCMotionStreak.m

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/CCNode.m

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/CCParallaxNode.m

/Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/CCNode.m:321:77: warning: 

      format specifies type 'unsigned int' but the argument has type 'CCNode *'

      [-Wformat]

  ...stringWithFormat:@"<%@ = %08X | Tag = %i>", [self class], self, tag_];

                              ~~~~                             ^~~~

                              %8@

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/CCParticleExamples.m

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/CCParticleSystem.m

1 warning generated.

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/CCParticleSystemPoint.m

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/CCParticleSystemQuad.m

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/CCProgressTimer.m

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/CCRenderTexture.m

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/CCRibbon.m

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/CCScene.m

/Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/CCRibbon.m:314:89: warning: 

      format specifies type 'unsigned int' but the argument has type

      'CCRibbonSegment *' [-Wformat]

  ...= %08X | end = %i, begin = %i>", [self class], self, end, begin];

       ~~~~                                         ^~~~

       %8@

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/CCScheduler.m

1 warning generated.

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/CCSprite.m

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/CCSpriteBatchNode.m

/Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/CCScheduler.m:125:92: warning: 

      format specifies type 'unsigned int' but the argument has type 'CCTimer *'

      [-Wformat]

  ...= %08X | target:%@ selector:(%@)>", [self class], self, [target class], ...

       ~~~~                                            ^~~~

       %8@

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/CCSpriteFrame.m

/Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/CCSprite.m:275:126: warning: 

      format specifies type 'unsigned int' but the argument has type

      'CCSprite *' [-Wformat]

  ...%08X | Rect = (%.2f,%.2f,%.2f,%.2f) | tag = %i | atlasIndex = %i>", [self class], self,

     ~~~~                                                                              ^~~~

     %8@

/Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/CCSpriteBatchNode.m:120:77: warning: 

      format specifies type 'unsigned int' but the argument has type

      'CCSpriteBatchNode *' [-Wformat]

  ...stringWithFormat:@"<%@ = %08X | Tag = %i>", [self class], self, tag_ ];

                              ~~~~                             ^~~~

                              %8@

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/CCSpriteFrameCache.m

/Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/CCSpriteFrame.m:67:124: warning: 

      format specifies type 'unsigned int' but the argument has type

      'CCSpriteFrame *' [-Wformat]

  ...%08X | TextureName=%d, Rect = (%.2f,%.2f,%.2f,%.2f)> rotated:%d", [self class], self,

     ~~~~                                                                            ^~~~

     %8@

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/CCTMXLayer.m

1 warning generated.

1 warning generated.

1 warning generated.

1 warning generated.

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/CCTMXObjectGroup.m

/Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/CCSpriteFrameCache.m:83:95: warning: 

      format specifies type 'unsigned int' but the argument has type

      'CCSpriteFrameCache *' [-Wformat]

  ...= %08X | num of sprite frames =  %i>", [self class], self, [spriteFrames...

       ~~~~                                               ^~~~

       %8@

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/CCTMXTiledMap.m

1 warning generated.

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/CCTMXXMLParser.m

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/CCTexture2D.m

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/CCTextureAtlas.m

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/CCTextureCache.m

/Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/CCTexture2D.m:183:128: warning: 

      format specifies type 'unsigned int' but the argument has type

      'CCTexture2D *' [-Wformat]

  ...%08X | Name = %i | Dimensions = %ix%i | Coordinates = (%.2f, %.2f)>", [self class], self...

     ~~~~                                                                                ^~~~

     %8@

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/CCTexturePVR.m

/Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/CCTextureAtlas.m:113:85: warning: 

      format specifies type 'unsigned int' but the argument has type

      'CCTextureAtlas *' [-Wformat]

  ...stringWithFormat:@"<%@ = %08X | totalQuads =  %i>", [self class], self, ...

                              ~~~~                                     ^~~~

                              %8@

1 warning generated.

1 warning generated.

/Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/CCTextureCache.m:115:4: warning: 

      format specifies type 'unsigned int' but the argument has type

      'CCTextureCache *' [-Wformat]

                        self,

                        ^~~~

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/CCTileMapAtlas.m

1 warning generated.

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/CCTransition.m

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/CCTransitionPageTurn.m

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/CCTransitionRadial.m

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/Platforms/Mac/CCDirectorMac.m

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/Platforms/Mac/CCEventDispatcher.m

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/Platforms/Mac/MacGLView.m

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/Platforms/Mac/MacWindow.m

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/Platforms/iOS/CCDirectorIOS.m

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/Platforms/iOS/CCTouchDispatcher.m

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/Platforms/iOS/CCTouchHandler.m

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/Platforms/iOS/EAGLView.m

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/Platforms/iOS/ES1Renderer.m

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/Platforms/iOS/glu.c

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/Support/CCArray.m

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/Support/CCFileUtils.m

/Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/Platforms/iOS/ES1Renderer.m:188:81: warning: 

      format specifies type 'unsigned int' but the argument has type

      'ES1Renderer *' [-Wformat]

  ...stringWithFormat:@"<%@ = %08X | size = %ix%i>", [self class], self, back...

                              ~~~~                                 ^~~~

                              %8@

1 warning generated.

/Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/Support/CCArray.m:294:94: warning: 

      format specifies type 'unsigned int' but the argument has type 'CCArray *'

      [-Wformat]

  ...stringWithFormat:@"<%@ = %08X> = ( ", [self class], self];

                              ~~~~                       ^~~~

                              %8@

1 warning generated.


コンパイル過程で、LLVMっぽいWarningが出ている。


Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/Support/CCProfiling.m

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/Support/CGPointExtension.m

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/Support/TGAlib.m

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/Support/TransformUtils.m

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/Support/ZipUtils.m

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/Support/base64.c

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/Support/ccUtils.c

Compiling /Users/highvision/Desktop/tweejump/tweejump/libs/cocos2d/cocos2d.m

Compiling /Users/highvision/Desktop/tweejump/tweejump/main.m

Preprocessing System/verde/config.m.m4

Compiling Build/android-armeabi-debug/tweejump/config.m

Archiving Build/android-armeabi-debug/tweejump/apk/lib/armeabi/libconfig.a

Indexing Build/android-armeabi-debug/tweejump/apk/lib/armeabi/libconfig.a

Archiving Build/android-armeabi-debug/com.iplayful.tweejump/tweejump/libtweejump.a

Indexing Build/android-armeabi-debug/com.iplayful.tweejump/tweejump/libtweejump.a

Linking Build/android-armeabi-debug/tweejump/apk/lib/armeabi/libverde.so

Saving build configuration

Packaging resources.

Packaging assets/fps_images.png

Packaging assets/Icon-Small-50.png

Packaging assets/Default.png

Packaging assets/Icon-72.png

Packaging assets/Icon-Small.png

Packaging assets/Icon-Small@2x.png

Packaging assets/Icon.png

Packaging assets/iTunesArtwork

Packaging assets/bitmapFont.fnt

Packaging assets/bitmapFont.png

Packaging assets/changePlayerButton.png

Packaging assets/playAgainButton.png

Packaging assets/sprites.png

Packaging ATTRIBUTION.txt

Packaging assets/Info.plist

Dexing classes.

Packaging classes.dex

Packaging lib/armeabi/libverde.so

Packaging lib/armeabi/gdbserver

Packaging lib/armeabi/libv.so

Packaging lib/armeabi/libcxx.so

Packaging lib/armeabi/libSystem.so

Packaging lib/armeabi/libobjc.so

Packaging lib/armeabi/libffi.so

Packaging lib/armeabi/libpthread_workqueue.so

Packaging lib/armeabi/libdispatch.so

Packaging lib/armeabi/libFoundation.so

Packaging lib/armeabi/libBridgeKit.so

Packaging lib/armeabi/libOpenAL.so

Finalizing Build/android-armeabi-debug/tweejump/tweejump-unaligned.apk

Signing APK with keys

Aligning Build/android-armeabi-debug/tweejump/tweejump-signed.apk

Loading...

Waiting for device...




で、デバイス側への転送が始まる。

手元のアレな端末で試したところ、まあ動く。



UIKit全開なものを変換するとどうなるのか

→https://groups.google.com/forum/?fromgroups#!topic/apportable-discuss/jVR7FOa61_U

StoryBoardからのものは無理。

xibからのものは出る、、ほんとか?


→UIWindowへの直接の追加は無効

色指定すら無視された、、上になんもないのに、、


→xibで追加されるViewへの特定の変更は有効

色指定が効いた(ブワッ

コード、xibともに効果が確認できた


ボタンの追加は、xibからならOK

ただしデフォルト無指定の場合、枠線が出ない。


スクリーンショット 2013-07-05 11.09.25.png

iPhoneSimulator 640 x と、Android4.1 720 x1280

スクリーンショット 2013-07-05 11.13.05.pngサイズ未調整.png


出た。 で、ScreenというかView基底というか、UIWindowに対して処理を書く事で、

スクリーン比に合わせた変換が出来る。と。

#ifdef ANDROID

    [UIScreen mainScreen].currentMode =

    [UIScreenMode emulatedMode:UIScreenAspectFitEmulationMode];

#endif

で、

1__#$!@%!#__スクリーンショット 2013-07-05 11.13.05.pngScreenshot-2013-07-05.png

比率的にはだいたい一緒になったのでは!!

比率的な話でいうと、セットしている「Windowに対して等倍になる」というオプションのおかげで、

画面サイズ 720 x 1280に対して、xibのレイアウト特性がちゃんと出た状態で描画されている。


→で、ボタン押せるの?

- (IBAction)touch:(id)sender {

    [self.view removeFromSuperview];

}

が効いた。ちゃんと動いてる。ビュー消える。

アニメーションとかはどうなのかなー、UIAnimation試そう。



→ボタンの背景画像は?

出た。

ずれてるように見えるのは、_をフォントで書いているので、フォントサイズの変化によるモノだと思う。

たぶん前からこうなってるんだけど、背景が出た事で見えるようになった感じ。

1__#$!@%!#__Screenshot-2013-07-05.png


→UIAnimationは?

効かないっぽい。

ぐあああああああああああああ惜しいいいいいいいいいいいいいい



→Rotationは?

iOSと全く同じ、というかxibで指定したデフォルト動作が再現された。

ただ、AutoLayoutと旧式のレイアウトだと、旧式レイアウトのほうがちゃんと表示される気がする。

比較不足。

Android側で1pxくらい下線がでてるのは、Screenshotの都合っぽい。

スクリーンショット 2013-07-05 12.17.00.png縦.png


スクリーンショット 2013-07-05 12.37.41.png2__#$!@%!#__Screenshot-2013-07-05.png



→UITableとか、UITextViewとか

ちゃんと出てる感ある。Cellとかで細かい事したらどうなるかな。

TextFieldはちゃんとキーボードでたし打てたしイベント伝達もした。

3__#$!@%!#__Screenshot-2013-07-05.png



→UIWebView

xibで他のビューに内包したものだと、ローディングが開始されなかった。

単独のビューとして生成した場合、ちゃんと機能した。



ざっくりと変換OKだったもの

OpenGLESでのお絵描き

OpenAL系

AudioFramework系

このへんはOKだった。

NSTimerやDate系での時間を計った動作

OKだった。


GCD系

OKだった。


UIWebview

OKだった。

ただし、ビューの入れ子にすると正しく初期化されないぽい。

浅いレイヤーでベースに対して置く分にはOK。



ざっくりと変換が駄目だったもの

日本語

ラベルとかに貼ると文字化けJK


AFNetworking

no visible @interface for 'UIImage' declares the selector "initWithData:scale:" ネットワークとは別の理由で駄目。っぽい。


GPUImage

OpenGL系の定数宣言が無くアウトになる。

unknown type name 'CVOpenGLESTextureCacheRef'

unknown type name 'CVPixelBufferRef'

unknown type name 'CVOpenGLESTextureRef'

unknown type name 'CVPixelBufferRef'

プロパティが読めないとかなのかな。


PhotoPicker

AVBasicVideoOutput

カメラ系は駄目。

ゲームにフォーカスしているからかなーという読み。



apportableに関連したプロジェクトの管理について

Xcodeプロジェクトがある場所でapportableの各種コマンドを実行するのだけれど、

.sconsign.dblite

でいろいろ管理しているっぽい。っていうかXcodeのprojと同じ階層にぽいっと何か吐かれるので、こう、不味いことになりそう。


本題、内部変換的にどうなっているのか

ログ見るとだいたい解るような。

と思ったら

Seasonsさんという方がためになる死霊をupしてくださっていました。

http://www.slideshare.net/seasons/apportable-meeting



アプリケーションパッケージはどうなっているのか

Android用のパッケージが、下記に吐かれている。

/Users/ユーザー名/.apportable/SDK/Build


ここに、android-armeabi-debugフォルダが出来ていて、

中はこんな感じ。

スクリーンショット 2013-07-05 5.06.48.png

java、java-classes フォルダは 空だった。

途中の生成に使ってるのかなーって監視してみたけど、特になにも、、



apportableコマンドラインをドカッとはりつけ

highvision:SimpleWindowApp highvision$ apportable -h

usage: apportable [-h] [-v [VERBOSE_FLAGS]] [-j [NUM_JOBS]]

                  [--debug-scons DEBUG_SCONS] [--no-xcode] [--no-merge]

                  [--generate] [--target TARGET] [--xcode-project PROJECT]

                  [--xcode-workspace WORKSPACE] [--xcode-config CONFIGURATION]

                  [--xcode-target TARGET] [--xcode-scheme SCHEME]

                  [--xcode-sdk SDK] [--xcode-arch ARCH] [--fast-mode]

                  [--profile PROFILE] [--build-flags BUILD_FLAGS]

                  [--custom-params CUSTOM_PARAMS] [--version]

                  [--tools UPDATE_TOOLS] [--confirm-stable-updates]

                  [--use-clang-version USE_CLANG_VERSION]

                  [--use-gdb-version USE_GDB_VERSION]

                  [--use-sdk-version USE_SDK_VERSION]

                  [--use-ndk-version USE_NDK_VERSION]

                  [--use-vorbistools-version USE_VORBISTOOLS_VERSION]

                  [--use-m4-version USE_M4_VERSION] [--ninja]

                  

                  [{load,kill,just_debug,log,clean_assets,just_debug_java,copy_and_debug,build,analyze,update_toolchain,profile,clean,screenshot,copy_and_load,update,just_profile,dump_env,dst_clean,just_load,patch,debug_java,install,debug,clean_device_cache,uninstall}]


positional arguments:

  {load,kill,just_debug,log,clean_assets,just_debug_java,copy_and_debug,build,analyze,update_toolchain,profile,clean,screenshot,copy_and_load,update,just_profile,dump_env,dst_clean,just_load,patch,debug_java,install,debug,clean_device_cache,uninstall}

                        Invoke a build action. default = build


optional arguments:

  -h, --help            show this help message and exit

  -v [VERBOSE_FLAGS], --verbose [VERBOSE_FLAGS]

                        Verbose logging output. (compile,scons,signing,link,ex

                        plain,copy,builders,archive)

  -j [NUM_JOBS], --jobs [NUM_JOBS]

  --debug-scons DEBUG_SCONS

                        Comma-separated list of scons debug options (count,

                        dtree, explain, findlibs, includes, memoizer, memory,

                        objects, presub, stacktrace, stree, time, tree,

                        prepare, duplicate, randomdeps)

  --no-xcode            Disable Xcode invocations.

  --no-merge            Disable merging parameters (just use final).

  --generate            Force re-generation of Xcode derived parameters.

  --target TARGET

  --xcode-project PROJECT

                        Xcode project to generate parameters from (only

                        available on MacOS X).

  --xcode-workspace WORKSPACE

                        Xcode workspace to generate parameters from (only

                        available on MacOS X).

  --xcode-config CONFIGURATION

                        Xcode project configuration.

  --xcode-target TARGET

                        Xcode project target to build.

  --xcode-scheme SCHEME

                        Xcode project scheme to build.

  --xcode-sdk SDK       Xcode project sdk to build with.

  --xcode-arch ARCH     Xcode project arch to build for.

  --fast-mode           Disable header tracking and skip certain time costly

                        steps (note: this may be dangerous!)

  --profile PROFILE     Build with function profiling enabled.

  --build-flags BUILD_FLAGS

                        Display the build flags for a given file

  --custom-params CUSTOM_PARAMS

                        Add special environment switches for use with

                        conditional merge items. Note: this option is

                        potentially dangerous, use with care!

  --version             Show version information.

  --tools UPDATE_TOOLS  Comma-separated list of which tools you want to update

                        (eg: gdb,clang,android-ndk,android-sdk,ninja ). For

                        use with update_toolchain.

  --confirm-stable-updates

                        Automatically choose the stable variants of the

                        toolchain when updating

  --use-clang-version USE_CLANG_VERSION

                        Automatically choose this version of this tool when

                        updating the toolchain.

  --use-gdb-version USE_GDB_VERSION

                        Automatically choose this version of this tool when

                        updating the toolchain.

  --use-sdk-version USE_SDK_VERSION

                        Automatically choose this version of this tool when

                        updating the toolchain.

  --use-ndk-version USE_NDK_VERSION

                        Automatically choose this version of this tool when

                        updating the toolchain.

  --use-vorbistools-version USE_VORBISTOOLS_VERSION

                        Automatically choose this version of this tool when

                        updating the toolchain.

  --use-m4-version USE_M4_VERSION

                        Automatically choose this version of this tool when

                        updating the toolchain.

  --ninja               Use ninja to build.

ninja.pyってのがToolChainに入ってたがそれだろうか。

ちなみにninjaはIndieにしか含まれないっぽい。


Build actions:

互いに内包したりしてるタスク集。MavenでいうGoalみたいなの。


  build:           Compile c/c++/objc/objc++/java sources and create

                   application archive.


ビルド成果っていうかアーカイブが作られる場所が大変特殊で、

/Users/ユーザー名/.apportable/SDK/Build

の下に作られる。


  install:         Invoke the <build> phase, and install the application on a

                   connected device/emulator.

  load:            Invoke the <install> phase and launch the application.


  uninstall:       Uninstall app from device.


  kill:            Kill running app on device.


  screenshot:      Take a screenshot and save it into the current directory


Native Debugging:

  debug:           Invoke the <load> phase and attach the debugger (gdb).


  just_debug:      Launch the application and attach the debugger (no build

                   or install phases are invoked).


  log:             Show the system log for the attached device.


  clean_device_cache: Delete the cache of device libraries.  Use this if you

                      are having problems debugging on a device.  Next time

                      you debug, it will redownload all of the device

                      libraries.


Java Debugging:

  debug_java:      Invoke the <load> phase and attach the Java debugger (jdb).


  just_debug_java: Launch the application and attach the Java debugger (no

                   build or install phases are invoked).


Profiling:

  profile:         Invoke the <load> phase in profiler mode and load the

                   Profiler tool.


  just_profile:    Launch the application in profiler mode and load the

                   Profiler tool (no build or install phases are invoked).


Toolchain Managment:

  update_toolchain: Update the currently installed toolchain


  update:           Update the SDK


プラン、IndieとかProとかEnterpriseとか

Free  < 超えられない壁 < Indie < 超えられない壁 < Pro = Enterprise

なのかなーまだ良く解ってないけど。


Indie触ってみた感想だと、UIKit周りが出せるのがIndieからなので、

それ以下だとUI的な旨味はゼロになる印象。


まーUIはルールがー


みたいな話になるけどな。


気になった事

ARCはどうなってしまうのか

問題ないような。


Javaで追記できるのか

できた。


Unityとかは?

Freeだと無理。

適当に作ったプロジェクトを動かそうとしたが、apportable load自体でエラーが出た。

Indieだと動かせるのかな。


Storeとかは?

組み込みのものがあってそこにブリッジされるみたいなものすごい事がさらっと書いてあったが、

どうなっているのやら。

AndroidのVersionごとに微妙に差異があるのをどう解消してるのかな。とか、

一時保存とかどうしてるのかな、とか、

リストアとかのときどうするの?とか



まとめ

かなり根本的な機構から移植というか動作可能コンバートというか、稼働するようになっているので、

上辺だけの変換ではなく、根っこから誠実に実装されてるんだなーという感じがする。


UIKitでのレイアウトが生かせるのは、その部分だけ考えても大変有用なのでは。

wrote 2013/07/02 15:27:34

25分くらいの、SublimeSocketAssetUnity Tutorialを改造する動画


概要

日本語でおkって言われたのと、新verのお披露目がてら作った。


Unityの公式が展開してるTutorialプロジェクト

http://japan.unity3d.com/developer/document/tutorial/my-first-unity/01.html

の続きを、SublimeSocketAssetでライブコーディングしてみよう、というもの。



25分くらいのライブコーディングなのでアニメ見ながら一本ゲームができる多分きっと


並べて再生してほしい25分くらいのイカすアニメ

リトルウィッチアカデミア



そう、CMだよっ

1.4.x系が無事審査とおりました! やったね!

https://www.assetstore.unity3d.com/#/content/8003


wrote 2013/06/25 11:41:10

Unity AssetStoreになんか出してみるまでの記録というか備忘録


概要

SublimeSocketAsset(https://www.assetstore.unity3d.com/#/content/8003)を作ってUnityのAssetStore上に出すまでの記録。

激しくいろいろ楽だった。



入り口

UnityのWebトップから、AssetStoreの項目を選ぶ。

http://japan.unity3d.com/asset-store/


と、その下の方に、ストアで販売|販売条件|パブリッシャー運営、とかいかにもそれっぽいコーナーがあるので、ここから始める。



コンテンツ提出方法

http://japan.unity3d.com/asset-store/submit-content

ここに書いてある事を上から順にやるだけ。わー簡単。



ルール

アセットストアプロバイダー契約アセットストア提出ガイドライン を読もう。

日本語訳いいな、あったんだ いいな。 知らずに訳そうとした俺の黒歴史なんかどうでもいい!



Assetを登録する用のAssetをゲット

AssetStoreへのAssetの登録も、Assetで行う。

アセットストア ツール

こんな構成のAsset。

スクリーンショット 2013-06-22 1.31.41.png


このAsset取得後、メニュー -> Asset Store Tools -> Package Manager から、

スクリーンショット 2013-06-22 1.35.07.png


で、初回時はアカウントも何も無いと思うので、

NameとPassつけて、アカウントの作成を行う。

スクリーンショット 2013-06-22 1.32.28.png

Storeにぶっ飛ばされて詳細入力。素直に英語で入れるのがいいと思う。

スクリーンショット 2013-06-22 1.34.05.png


アカウント作成後、Assetの設定をいろいろと

再びAssetStoreManagerへ。

右上のPublisher Account から、パブリッシャー情報(ロゴとかサイトとか)の設定をする。

スクリーンショット 2013-06-22 1.39.01.png

あとは、投稿したいAssetについて書く -> Preview の繰り返しでなんとかなるはず。 特に挫ける要素は無い。

スクリーンショット 2013-06-22 8.36.53.png


注意点っつーかハマりポイント

・画像をセットできるんだけど、Preview上での表示順がカオス?

ファイル名、投稿順ともに関係ない。

非同期にupしてるっぽいので、投稿の終了順、とかなのかな。

意図した順番に左から並べるのにちょっと困った。



・表示されてるpixel数 横x縦 と、実際の表示される領域が異なる

アイコン画像とかには、AssetStore側で文字が載る。

、、だけじゃなくて、表示領域は画像サイズそのままではない。


メニュー -> Asset Store Tools -> Package Manager から、Key Image Templates 使ってなんとかするのが常道らしい。

自分は使うの忘れてた。

スクリーンショット 2013-06-22 8.25.39.png

画像サイズそのままが表示されるのではなく、トリミングされるので、まあ試しながらやるといいよ的な。



・Upload時のミスが多い

通信状態に関わらず、いざUploadしよう! というタイミングで、Uploadゲージが0%から進まなかったりする。

けっこうする。


わかっているご機嫌取りの方法としては、

・Unityごと再起動する

これがよい。


原因はわかんないけど。フォーラムとかでも見かけるので、わりとメジャーな出来事らしい。

惜しい、、、、!!


・Upload直後、AssetBundle にはそんなの含めないよ~ Warning みたいなのが出る

.dll、.rtfや、バイナリなどを含んだAssetをUploadしたときに出る。


心底焦る。

Uploadが終わったタイミングで、.dll file couldn't include asset bundle ~ みたいな文言が出て、


「えっ.dll含んじゃいけなかったの!? 作り方不味かった!?」

とか

「えっバイナリ、、弾かれて他のだけアップされちゃったの、、? 審査がこの後ある状態なんでsyアババババ」

とかなった。心理的に。


実際には、ちゃんとアップされる。

審査通ったの見て愕然としたけど。ちゃんとアップされてる。


AssetBundle化処理が同時に走ってるのはなんでなんだろう。


このへんの警告が出る事に対して、何の解説も見つけられず、全然理解できなかった。

スッゲー怖かったが、大丈夫、アップされる。


dllの作り方とかは、

Unity用に、複数ファイルをmcsでコンパイルするだけの簡単なお仕事

http://sassembla.github.io/Public/2013:03:30%206-48-06/2013:03:30%206-48-06.html


とかに書いておいた。


・exeバイナリのexeutable属性が消える

ちょっと実験じみた内容だったのだけれど、Mac用のexeファイルをAssetに含んでみた。

で、ハマッた。


AssetStore経由で取得したバイナリは、下記のように権限が変わる。

手元:-rwxr-xr-x  1 highvision  staff  19048  6 12 01:04 SwitchApp

GET:-rw-r--r--  1 highvision  staff  19048  6 20 11:10 SwitchApp


ずっとGithubとかからDLして模擬で試していたので、気づかんかった。なるほゲフゥ


SSA 1.3.x系はこのバグを抱えている。FAQ見て解決できるけど、玄人向けになってしまった。

審査中の1.4.x系で解消されてるので、審査完了待ち。



審査を待つ

で、Package Managerでのupが終わったら、メールが届くので、審査完了を待つ。

審査状況は、メニュー -> Asset Store Tools -> Publisher Administration から把握できる。


スクリーンショット 2013-06-22 9.12.33.png

ブラウザが開くので、はい。


審査にかかる期間と内容

iOSであるような、有償のAssetを販売するためにEINが~とか

企業だと~の提出が必要、とかそういうのがない。


入金先の指定などは、上記 Publisher Administration から出来る。

Paypal無双。


審査には2~3日とかそんな感じに書いてあるけど、自分が出したタイミングだと4~5日経ってもなんにもなくて、

「今混んでるから! 大丈夫ちゃんと審査してるよ☆彡(ノ゜▽゜)ノ☆ 次は10日後に連絡よこせいいな!?」

みたいなメールが返ってきた。


速いときは4~5日有れば南下のリアクションが返ってくると思う。



ほかにもなんかあった気がするけど、メモ見る限りだとこんな感じだった。


wrote 2013/06/21 20:04:01

UnityのコードをSublimeTextで編集するAsset、販売中


概要

身内間でのみ出してたやつ、やっとUnityのAssetStoreに出せた(SublimeSocketAsset)ので、

その他のものと合わせて、SublimeTextでUnity、こんなに便利なんですよ!! 的なまとめを作ることにした。

機能的に「この機能は、ここに載ってないこの機構でもできるよ!」ってのは有ると思うんだけど、

独断と偏見で比べて、まだマシなほうを残していたりする。


判断基準は

・疎結合かどうか。強烈なパス依存とかがあるとドン引き。

・非同期かどうか。コンパイルの度にプチフリするIDEとかつらい。


あとショートカットはMac用で書いてある。


STにUnity C#のシンタックスハイライトを導入

C#で書いていても、Unity用のキーワードとか基底クラスを特別扱いしたい。

専用のシンタックスハイライトがあって便利。


Package Controlから入れると楽。

Command Palette -> package Control: Install Package -> Unity3D


UnityのAPIから補完

Unity C# Snippets

Command Palette -> package Control: Install Package -> Unity C# Snippets

スクリーンショット 2013-06-21 3.35.05.png

時々、APIの情報が古いのか、パラメータの型情報が誤ったやつを出してくるのがあるけど、えらい捗る。


キーボードショートカットでコメントアウト/イン

コメントアウト&インを、command + / などのショートカットからなんとかしたくなるのが人情。

http://www.holoville.com/blog/?p=512


っていうかC#もできないので、そういう文化がない言語なんだな。

MonoDevelopにも無い。


いや良いけど。できるようになるので便利。



エラーとかの行をUnityコンソールからSublimeTextで開く

Unity editorでコンソールを表示した際、エラー内容をダブルクリックで対象の行に

フォーカスした状態でファイルを開く。

http://www.jacobpennock.com/Blog/?p=568

UnityHelperの話も出てるんだけど、個人的にはDashのほうが好き。


今後SublimeSocketAssetに積もうかなーと考えている。



STからUnityのドキュメントを開く

Dashと、

https://itunes.apple.com/jp/app/dash-docs-snippets/id458034879?mt=12


STからDashを起動するプラグイン

Command Palette -> package Control: Install Package -> DashDoc

の組み合わせが、異常に強力。

STでコードを書いている途中、補完が出力したAPIを選択した状態で

Command Palette -> DashDoc: invoke Dash with selected word(syntax-sensitive) 

or

control + alt + h


STのシンタックスハイライトを見て、何が見たいか絞ってくれるので良い。

スクリーンショット 2013-06-21 3.40.18.png




~ここからSublimeSocketAssetの独壇場~

SublimeSocketAsset

https://www.assetstore.unity3d.com/#/content/8003



STからUnityのコンパイルを行う

SublimeTextのビルドシステムを使ったものも有ったんだけど、Unityのパスを手で入れなければならず、

密結合で面倒だったので、SublimeSocketAssetで疎結合にした。


既存リリースの1.3.xだとインストール手順が2段階あって煩雑だが、

申請済みの1.4.x系が通れば、楽になる、、と思う。少しは。

FAQに書いてしまっているレベル。

https://github.com/sassembla/SublimeSocketAsset-support


編集→保存→コンパイル、が非同期にできる。

コンパイルにはUnity自体を使用しているので、Unityでのちゃんとしたビルド結果を取得する事が出来る。


Unityから開いたファイル以外でもコンパイルターゲットにできる。

つまりUnityのファイル監視機構に依存していない。

この辺の手法は、過去の記事とかを見ると何したか察しがつくと思う。


Unityにスクリプトのコンパイルを依頼するためにどう土下座すれば

http://sassembla.github.io/Public/2013:03:17%2013-53-03/2013:03:17%2013-53-03.html



ST上にUnityのコンパイルエラーを出す

無かったので作った。下記エラーやWarningが発生した際、ST上にライブで表示される。

一部、SublimeSocketAsset 1.4.xから対応が増えるかもしれない。


対応しているエラーを無理矢理発生させたのが下の写真。

各行左の丸いのをクリックすると詳細がST上とMacのNotificationに表示される。

スクリーンショット 2013-06-21 4.21.57.png

対応エラー一覧


Exception一般

以下に含まれないエラー一般。

Warning一般

unusedとか。


NullReferenceException

ぬるぽ。 ガッされてしまえ。


ArgumentException

いつ発生するのか忘れた。


You are trying to create a MonoBehaviour using the 'new' keyword.

MonoBehaviourなものを知らずnewしてると出る。実行時に検出される。エラーではないので止まりはしないが、コード上に表示されるようにした。


transform.position assign attempt for ~

Nullな要素のVector3をTransform.positionとかに代入しようとすると出るエラー。式算出とかだと出くわす。


UnityException

いつ発生するのか忘れた。


IndexOutOfRangeException

読んで字のごとく。


InvalidOperationException

いつ発生するのか忘れた。



特筆すべきは、NullなVectorをtransformに対してセットしてしまった時のレアーーーなエラーとか、UnityExceptionが実行時にコード上に直に表示されるところ。

捗るぞ。


ちなみにError/Warning表示はSublimeText自体のログにも出る。

スクリーンショット 2013-06-21 4.50.20.png

InvalidOperationとかいつ出たんだか、、、本当に忘れた。

ほかにもエラーが有ったら教えてほしく。


これらのエラーは検出機構からして1ファイルで設定/拡張可能にしてあるので、自前でエラーを定義してアクションを追加したりできる。



ST上にUnityの動作中のパラメータを出す

無かったので作った。

特定のDebug.Log形式でパラメータをST上に表示できる。

複雑な条件の中に入ったかどうかとか、ログに特徴的な事を書いてUnityのコンソールから探す、とかするのシンドイので、通ったところが光るのが重宝する。

Debug.Logの中身をL: から始めるだけ。


livelog.png



今後のやる気


独自型の補完を出す

1.5.xには入れられると思う。


エラーのQuickFixを出す

ST3から導入できる。強力。


Windows版

ST3の正式版が出たら、Windows版に対応。

でもWinの人はVS使えば良いと思うが。


STからのUnity editor Play

やりたい。


次のエラー行へのジャンプ

いちいちUnityのコンソールを経由するのが面倒なので、

キーバインドかなにかで次のエラーがあるファイル/行を表示するとかしたい。


コード上への負荷表示

コード間の時間的負荷を、コード上に表示したい。


ST上への全値のフィルタ表示

全値に対して、Debug.Log("L:") を仕込まないでもできる、、かもしれない。実験中。



などなど。リクエスト有れば聞くだけ聞きたいです。


そんなわけで、宣伝だった。


wrote 2013/06/21 1:44:53

Unity Asset Store Provider Agreementの和訳がすでに有ったのに


概要

これの和訳をしてみんとす。みんなーアセットつくろーぜー。

http://unity3d.com/company/legal/as_provider


→すでにあった!! 嘗めてたスイマセン!!

http://japan.unity3d.com/company/legal/as_provider


やー自分の探し方が悪かった。

japan.つければ大概のものは見つかるんじゃないか、、

教えてくれた 各位 ありがとうございます。



以下内容

見る価値は無い。


1.

Background 

1.1

The Unity Asset Store is a publicly available site on which Providers and Unity can distribute Assets to Customers.

Unityアセットストアとは、Unityやアセットプロバイダがアセットを客へと配布できる場所である。


1.2

This Agreement regulates the legal relationship between Provider as a content creator and Unity as the operator of the Unity Asset Store.

本契約書(Agreement)は、コンテント制作者としてのアセットプロバイダと、ストアの管理者としてのUnityの法的な関係について取り決めるものである。


1.3

The purpose of the Agreement is to establish the legal framework for the Providers distribution of their Assets via Unity's online and in-editor asset store service.

この契約文の目的は、プロバイダが自身のアセットをUnityのオンライン/エディタ組み込みストアサービスを介して配布するための法的な仕組みの基礎になること。


1.4

This Agreement is intended to protect the interests of Provider as well as those of Unity. Provider has been encouraged to examine this Agreement carefully and has been given the opportunity to ask clarifying questions prior to signing.

(途中)この契約文は、プロバイダ、Unity双方の利益を守ることを意図している。


 

2.

Definitions

2.1

For the purposes of this Agreement with pertaining appendices, the below terms shall have the following meanings unless otherwise stated or clear from the context:

本契約と付録において、以下の用語は、文脈から定義、または無効化しない限り、次の意味のものとする。


 

"Agreement"

This Asset Store Provider Agreement with pertaining appendices.

付録を含めたこの契約自体を指す


 

"Assets"

Assets shall mean (i) software designed in order to facilitate the development of electronic games (ii) content (for example – without limitation – computer graphics, including 3D computer graphics, sounds and music), tutorials and other digital materials created in order to become integrated parts of electronic games and interactive media in accordance with the Unity Asset Store Guidelines in force at any time, and distributed via the Unity Asset Store.

アセット は以下の内容を意味する

1.ビデオゲーム開発促進のために設計されたソフトウェア

2.3Dのグラフィックスデータ、サウンド、音楽&それ以外のもの など、チュートリアルなど、インタラクティブなゲーム、メディアを指す。

Unityのアセットストアのガイドラインに基づいて、Unity アセットストアを介して配布されるものを指す。


 

"Brand Features"

Any trade name, trade mark, service mark, logo, domain name, and other distinctive brand feature of each Party, respectively, as owned (or licensed) by such Party from time to time

あらゆる商号、商標、サービスマーク、ロゴ、ドメイン名


 

"Customer"

Any person, company or other legal entity that will acquire licenses to Assets via the Unity Asset Store.

Unityアセットストアを経由してライセンスを獲得する会社または個人


 

" Incorporated Content"

Content that cannot be extracted from an Asset and used as stand-alone content without the use of reverse engineering tools or techniques, and which is not intended to be further distributed outside of the Asset that contains the Incorporated Content.

(まだ)


 

"Provider "

Any person, company or other legal entity who has accepted this Agreement by clicking and who is registered and approved by the Unity Asset Store to distribute Assets in accordance with the terms of this Agreement

本契約の条項に従ってUnity アセットストアに登録された会社あるいは個人。


 

"Party" or "Parties"

Unity and/or Provider


Unityか開発者


 

"Payment Processor(s)"

Any party authorized by Unity to provide payment processing services of payment from Customers for Assets distributed via the Unity Asset Store.


Unityによって認証された、アセットストアで発生したユーザーからのアセット代を処理する会社


 

"Unity"

"Unity" Unity Technologies A/S, (CVR no. 30 71 99 13 ) Livjægergade 17, 1., 2100 København Ø, Denmark

ユニティ社


 

"Unity Asset Store"

The Unity Asset Store site operated by Unity, where Providers and Unity can distribute Assets directly to Customers.

Unityによって管理されている、プロバイダやUnityがアセットをユーザーへと直接配布することができる場所をさす

 

3.

Accepting this Agreement

3.1

This Agreement forms a legally binding contract between Provider and Unity, in relation to Provider's use of the Unity Asset Store to distribute Assets. In order to use the Unity Asset Store to distribute Assets, Provider must first agree to this Agreement by way of clicking to accept this Agreement where this option is made available to Provider. Provider may not distribute Assets on the Unity Asset Store if Provider does not accept this Agreement.

本契約は、資産を分配するユニティ·アセット·ストアのプロバイダの使用に関連して、プロバイダとユニティ間の法的拘束力のある契約を形成している。

プロバイダは、Unityアセットストアでアセットを配布するために、本契約に同意する必要がある


3.2

Any person who enters into this Agreement on behalf of Provider represents that he has full legal authority to bind Provider.

プロバイダとして本契約を締結したものは、その法的権限を負うものとする。


3.3

Provider expressly accepts and agrees that Unity shall be entitled to forward Providers name, address and other contact details to any third Party that reasonably claims that Provider does not have all intellectual property rights, including all necessary patent, trademark, trade secret, copyright or other proprietary rights, in and to Provider's Assets.

プロバイダは次の内容に同意することを表明するものとする。

プロバイダがアセットに対して必要なすべての特許、商標、企業秘密、著作権またはその他の所有権を含むすべての知的財産権を保持していないのが明確な場合(+クレーム?)、Unityは第三者にプロバイダの氏名、住所、その他の情報を転送する権利を有する。


4.

Pricing and Payments

4.1

This Agreement covers both Assets that Provider chooses to distribute for free and Assets for which Provider charges a fee. All fees for Assets distributed via the Unity Asset Store must be processed by the Payment Processor

本契約は無料、有料アセット配布の両方についてカバーする。

すべてのアセットストアで配布されるアセットの売り上げは、支払い処理業者によって処理されるものとする。


4.2

Provider may set the price for Provider's Assets in US Dollars (USD). For practical purposes all prices shall be fixed by Provider at full USD amounts. (For example prices set at 5.99 USD may not be applied). The Unity Asset Store may display to Customers the price of Provider's Assets in USD or other currencies that Unity may consider expedient. 

Unity may chose to set different prices in other currencies, and shall not be responsible for the accuracy of the prices set, or for currency and conversion rates.

プロバイダは、米ドルでのプロバイダの資産の価格(USD)を設定することができる。

すべての価格は、プロバイダによって、完全(整数)なUSDの金額で指定されなければならない。5.99とかは指定できない。

アセットストアでは、ユーザーへとドルまたは他の通貨(Unityの設定した為替によるもの)で価格表示がなされる可能性がある。

Unityがその他の通貨について米ドルと異なった価格設定をする可能性があるが、その他の通貨とコンバージョン率の正確性については責任を負わないものとする。


4.3

The prices that Provider sets for Assets or the prices that Unity sets in other currencies than USD (cf. clause ), whichever is applicable, will determine the amount of payment Provider will receive. 70 (seventy) percent of the sales price (less any refunds, bank fees related to the transfer to the Provider and less any taxes, levies and VAT or the like) will be remitted by Unity to the Provider. The remaining 30 (thirty) percent will be allotted to and retained by Unity

プロバイダが設定したアセットの価格 or Unityが米ドル以外の通貨で設定した価格から、プロバイダが受け取る額が決定される。

(払い戻し、銀行手数料、課徴金と付加価値税等などを考慮しない)

販売価格の70%がプロバイダに支払われる。残りの30%はUnityによって保持される。


4.3.1

PayPal Accounts Paid Monthly. The parties agree that any balance in favor of Provider will be calculated by Unity and made available to Provider via a web page. Unity will use reasonable efforts to pay Provider the applicable balance on a monthly basis as long as Provider provides and maintains a valid PayPal account.

(?)PayPalのアカウントによる支払いは、月ごとに支払われる。

支払額はUnityによって計算され、Webページを介してプロバイダに提供される。 Unityは、プロバイダが有効なPayPalアカウントを保持している限り、毎月プロバイダへと残額を支払うために合理的な努力を行うものとする。


4.3.2

Check or Wire Payments Paid Quarterly. If Provider fails to provide a valid PayPal account, Unity will pay balances above USD 250 to Provider on a quarterly basis by check or wire payment, less applicable bank fees. However, any such account balance in favor in of Provider of less than 250 USD at the end of a calendar quarter will not be paid. Instead, such balance below 250 USD will be transferred to the following calendar quarter. In the event that the balance for a period of eight consecutive calendar quarters remains below 250 USD, then Unity will pay such balance to Provider, less any bank fees related to the transfer to the Provider. The current applicable bank fees for check or wire payments are set forth in the Asset Store.

(まだ)


4.4

Provider is solely responsible for payment of any taxes, levies and VAT or the like on any payments it receives from Unity regardless of which taxing jurisdiction that has the authority to collect such taxes, levies and VAT or the like.

(まだ)


4.5

Provider may also choose to distribute Assets for free. If the Asset is free, Unity shall not be entitled to receive the 30 (thirty) per cent listed in Section above. Provider may not in the future collect charges from Customers for copies of the Assets that those Customers were previously allowed to download for free.

(まだ)


4.6

Special Refund Requirements

(まだ)

4.6.1

The Payment Processor's standard terms and conditions regarding refunds will apply except the following terms apply to Provider's distribution of Assets on the Unity Asset Store:


4.6.2

Assets that can be previewed by the Customer (such as static pictures): No refund is required or allowed other than Assets that violate this Agreement or are taken down pursuant to this Agreement.


4.6.3

Assets that cannot be previewed by the Customer (such as software): Provider authorizes Unity to give the Customer a full refund of the Asset price if the Customer requests the refund within 2 (two) weeks after purchase.


4.6.4

In the event that a Customer returns any Asset and/or receives a refund, all license rights granted herein terminate and under the EULA the Customer must immediately destroy any and all copies contained on any type of media under the control or possession of the Customer.


4.7

Provider Support

4.7.1

Provider will be solely responsible for support and maintenance of Provider's Assets and any complaints about Provider's Assets. Provider's contact information will be displayed in each Asset detail page and made available to Customers for customer support purposes.

プロバイダは、自身の配布するアセットに対してサポートとメンテナンス、クレームへと対応する義務を負うものとする。

プロバイダの連絡先情報はアセットの詳細ページに表示され、顧客サポートのために、ユーザーから参照できるようになるものとする。


4.7.2

Failure to provide adequate support for Provider's Assets may result in low Asset ratings, less prominent Asset exposure, low sales and billing disputes. In the event of disputes for Assets sold for less than 50 USD, Unity may at Provider's expense decide that the full purchase price shall be refunded to the Customer and charged back in full to the Provider, in addition to any handling fees charged by the Payment Processor. Chargeback requests for Assets sold at 50 USD or more will be handled in accordance with the Payment Processor's standard policy.

プロバイダが、提供するアセットへのサポートに失敗すると、アセットの評価の低下や売り上げの低下、販売不振につながります。

50米ドル未満で売られているアセットに関する揉め事が発生した場合、Unityはプロバイダの費用でユーザーへの返金を行う。手数料などもプロバイダが支払うものとする。

50米ドル以上で以上で売られているアセットのチャージバック要求については、支払い処理の標準ポリシーに従って処理される。


4.8

Reinstalls

4.8.1

Customers are allowed unlimited reinstalls of each Asset distributed via the Unity Asset Store, provided however that if Provider removes Asset(s) from the Unity Asset Store pursuant to clauses (i), (ii), (iii) or (iv) of Section 8.1.1, such Asset(s) shall be removed from all portions of the Unity Asset Store and Customers shall no longer have a right or ability to reinstall the affected Assets.

ユーザーは自身が購入したアセットに対して、Unityアセットストアから無制限に再インストールする権利を持つ。

ただし、clause1,2,3,4 または8.1.1などによってアセットのすべてがUnityアセットストアから削除された場合、ユーザーは再インストールの権利をもう持たないものとする。


4.9

Donations

4.9.1

Providers of free Assets may request and accept indirect donations for their work, provided that the following conditions are complied with:

無料アセットのプロバイダは、次の条件が遵守されていれば、自分の仕事のために間接的な寄付を要求してもよい。


4.9.1.1

Donations shall be handled via the Provider's own payment transaction system on their own website.

寄付は自分のウェブサイト上でプロバイダ独自の決済取引システムを介して処理されなければならない。


4.9.1.2

Provider's free Assets may not have a special enhanced version of this Asset which Provider markets outside of the Unity Asset Store (and thus circumventing the payment in favor of Unity, as specified in above.

無料アセットは別バージョンのアセットを売る機構をアセットストアの外部に持ってはならない。


4.9.1.3

Assets themselves may not explicitly mention, prompt or request donations when embedded in a built Unity project (executable, browser game, etc.) nor in the editor if it uses editor classes.

()


4.9.1.4

Donation requests shall be mentioned by use of the text: “donations accepted” on the Asset’s Asset Store page/description itself.

寄付の要求はテキストを使用することにより記載しなければならない:Unityアセットストアの紹介ページなどで、"寄付は受け入れた" など。

 

5.

Use of the Unity Asset Store by Provider

5.1

Except for the license rights granted by Provider in Section below, Unity agrees that it obtains no right, 

title or interest from Provider (or Provider's licensors) under this Agreement in or to any Asset supplied by Provider, including any intellectual property rights which subsist in those Assets.

以下のセクションでは、プロバイダによって付与されたライセンスの権利を除き、プロバイダから供給されたアセットに含まれる/に適応されるプロバイダ(またはプロバイダのライセンス管理者)が持つ権利、著作物、利益について、あらゆる知的財産権を含め、Unityは権利を持たない事に同意する。


5.2

Provider agrees to use the Unity Asset Store only for purposes that are permitted by (a) this Agreement and (b) any applicable law, regulation or generally accepted practices or guidelines in the relevant jurisdictions (including any laws regarding the export of data or software to and from Denmark or other relevant countries).

プロバイダは、以下の内容にて許可されている目的のためにユニティ·アセット·ストアを使用することに同意する。

(a)本契約

(b)該当する法律、規制、関連する法域において一般に公正妥当と認められるプラクティスやガイドライン

(デンマークや他の関係国からのデータまたはソフトウェアの輸出に関する法律を含む)


5.3

Provider agrees that Provider will protect the privacy and legal rights of Customers. If the Customers provide Provider with, or Provider's Assets access or use, Customer names, passwords, or other login information or personal information, Provider must make the Customers aware that the information will be available to Provider, and Provider must provide a legally adequate privacy notice and protection for those Customers. Further, Provider may only use that information for the limited purposes for which the Customer has given Provider permission to do so. If Provider's Assets store personal or sensitive information provided by Customers, it must do so securely and only for as long as it is needed and in full compliance with any applicable law regarding Provider's access or use of such information. But if the Customer has opted into a separate agreement with Provider that allows Provider or Provider's Asset to store or use personal or sensitive information directly related to Provider's Asset then the terms of that separate agreement and any applicable privacy laws will govern Provider's use of such information.

(未完成)

プロバイダは、お客様のプライバシーおよび法的権利を保護することに同意するものとする。

お客様とのプロバイダ、またはプロバイダの資産へのアクセスや使用を提供する場合には、顧客名、パスワード、またはその他のログイン情報や個人情報は、プロバイダは、情報がプロバイダに利用されることをお客様に認識させなければならず、プロバイダは、法的に適切な​​プライバシーを提供する必要があるものとする。


5.4

Prohibited Actions


Provider agrees that Provider will not engage in any activity with the Unity Asset Store, including the development or distribution of Assets, that interferes with, disrupts, damages, or accesses in an unauthorized manner the devices, servers, networks, or other properties or services of any third party including, but not limited to Customers, Unity, payment providers or any network operator.

(意訳:妨害すんな。)


5.4.1

Provider may not use customer information that Provider has obtained from the Unity Asset Store or Customers to sell or distribute Assets outside of the Unity Asset Store.

プロバイダは、Unityアセットストア外に資産を売却 or 配布 or ユーザーから取得した顧客情報を使用することはできない。


5.5

Non-Compete

5.5.1

Provider may not use the Unity Asset Store to distribute or make available any Asset whose primary purpose is to facilitate the distribution of Assets outside of the Unity Asset Store.

プロバイダは、Unityアセットストア外で別のアセットを配布・使用可能にするのを助長する目的でUnityアセットストアを使ってはならない。


5.6

Provider agrees that Provider is solely responsible for (and that Unity has no responsibility to Provider or to any third party for) any Assets Provider distributes through the Unity Asset Store and for the consequences of Provider's actions (including any loss or damage which Unity may suffer) by doing so.

プロバイダは、プロバイダがUnityアセットストアで配布するアセットに対するプロバイダの行動の結果について、

単独で責任を負い、またUnityがプロバイダや第三者に対して一切責任を負わない、という事に対して、同意するものとする。

(Unityが被る被害、ダメージに対しても含む。)


5.7

Provider agrees that Provider is solely responsible for (and that Unity has no responsibility to Provider or to any third party for) any breach of Provider's obligations under this Agreement, any applicable third party contract or terms of service, or any applicable law or regulation, and for the consequences (including any loss or damage which Unity or any third party may suffer) of any such breach.

(まだ)


5.8

Asset Ratings

5.8.1

The Unity Asset Store will allow Customers to rate Assets. Only Customers who download the applicable Asset will be able to rate it. Asset ratings will be used to determine the placement of Assets on the Unity Asset Store with higher rated Assets generally given better placement, subject to Unity's ability to change placement at Unity's sole discretion. Unity reserves the right to display Assets to Customers in a manner that will be determined at Unity's sole discretion.

Unityアセットストアはユーザーによってアセットの評価(レーティング)が行われる事を許可する。

そのアセットをダウンロードしたユーザーのみがアセットを評価する事ができる。

よい評価を得ているアセットには、一般的にUnityアセットストア内での良い配置を与えるものとする。

Unityは、自身の裁量により決定された方法でユーザーにアセットを表示する権利を有するものとする。


5.8.2

Provider's Assets may be subject to ratings to which Provider may not agree. In addition other factors that Unity deems relevant such as (but not limited to) community ratings and Provider's history may influence such ratings. Provider may contact Unity if Provider has any questions or concerns regarding such ratings.

プロバイダのアセットはプロバイダの望まない評価を受ける可能性がある。

Unityは、そのようなコミュニティの評価や、プロバイダの経歴をもとに、そのような評価がなされていると判断する。

プロバイダは、このようなの評価に関する質問や懸念を持っている場合、Unityを連絡することができる。


5.9

Marketing Provider's Assets

5.9.1

Provider will be responsible for uploading Provider's Assets to the Unity Asset Store, providing required Asset information to Customers, and accurately disclosing the security permissions necessary for the Asset to function on Customer's equipment. Assets that are not properly uploaded will not be published in the Unity Asset Store.

(まだ)


5.9.2

In addition Provider will be responsible for updating the Assets with new versions on the Unity platform.

プロバイダはUnityのアップデートに応じて、アセットのアップデートを行う責任を負うものとする。


5.10

Restricted Content

5.10.1

Provider agrees that it will not upload, post or otherwise transmit via the Unity Asset Store any Asset or other content, which is inaccurate, harmful, obscene, pornographic, defamatory, racist, violent, offensive, harassing, or otherwise objectionable to Unity or Unity Asset Store or Customers. In addition any Asset that Provider distributes on the Unity Asset Store must adhere to the Unity Asset Store Guidelines in force at any time. While Unity does not undertake any legal obligation to monitor the Assets or their content, Unity reserves the right to do so, and if Unity is notified by Provider or otherwise becomes aware and determines in its sole discretion that an Asset or any portion thereof that Provider has uploaded to the Unity Asset Store does not adhere to the Unity Asset Store Guidelines in force at any time, then Unity shall be entitled to demand that Provider edits and makes such other changes in the Asset, including – but not limited to – changes in materials and descriptions that form part of the Asset, for example with a view to adapt the Asset to the design of the Unity Asset Store and to avoid any defects in relation to the design of the Unity Asset Store. Finally Unity shall itself be entitled to edit and make such changes in the Asset. In addition Assets may be withdrawn from the Unity Asset Store at any time without prior notice at Unity's sole discretion.

(まだ)


5.10.2

Provider represents and warrants that images and text that is intended to market the Assets that Provider has uploaded to Unity Asset Store is truthful, accurate and does not misrepresent the Asset, for example – without limitation – by way of screen shots that do not match the content of the Asset.

(まだ)曲解されるような画像をUnityアセットストアに上げてはならない。

 

6.

License Grants

(まだ)

6.1

Provider grants to Unity a nonexclusive, worldwide, and royalty-free license to: copy, perform, distribute, modify, display, and use the Assets for administrative and demonstration purposes in connection with the operation and marketing of the Unity Asset Store and Unity's other products.

(まだ)


6.2

Except for the payment of the 70 (seventy) per cent listed in above Provider grants to Unity a non-exclusive, and royalty-free license to distribute the Assets from the Unity Asset Store.

(まだ)


6.3

Unity may use consultants and other contractors in connection with the performance of obligations and exercise of rights under this Agreement, provided that such consultants and contractors will be subject to the same obligations as Unity. After termination of this Agreement, Unity will not distribute Provider's Assets to Customers that have not previously licensed Provider’s Assets, but may retain and use copies of the Assets in order for Unity to be able to fulfill any obligations towards Customers that will survive the removal of an Asset from the Unity Asset Store (for example reinstalls cf. clause ).

(まだ)


6.4

Provider grants to Unity a non-exclusive, worldwide, time unlimited license to any Asset that Provider uploads to the Unity Asset Store in any medium now known or hereinafter invented to: (a) reproduce, license, and distribute Provider's Assets on Provider’s behalf; and to publicly perform, publicly display, digitally perform, or transmit for promotional and commercial purposes; (b) create and use samples of the Assets and the contents thereof for the purpose of demonstrating or promoting Provider's Assets or those of the Unity Asset Store; © use any trademarks, service marks or trade names incorporated in Provider's Asset in connection with Provider material; and (d) use the name and likeness of any individuals represented in Provider’s Asset only in connection with Provider's material.

(まだ)


6.5

Provider agrees that, pursuant to the EULA, it will grant to the Customer who acquires an Asset submitted by the Provider, a non-exclusive, worldwide, license in any medium now known or hereinafter invented to: (a) reproduce, post, modify, promote, license, sell, publicly perform, publicly display, digitally perform, or transmit the Asset for promotional and commercial purposes; (b) use any trademarks, service marks or trade names incorporated in the Asset; and © use the name and likeness of any individuals represented in the Asset.

(まだ)


6.6

All Assets that Customers purchase from the Unity Asset Store shall be subject to Unity's standard EULA, Appendix 1 unless Provider otherwise provides a EULA in accordance with Section 6.7 below.

(まだ)


6.7

Provider may deliver to Unity Provider's own EULA for any Asset at the time that Provider delivers the free Asset to Unity, provided, however, that Provider's EULA must include and may not be inconsistent with the minimum terms and conditions specified in Appendix 1 and must comply with all applicable laws in all countries where Provider wishes Unity to allow Customers to download the Assets. Unity shall allow each Customer to which Unity allows access to any such Asset to review Provider's EULA prior to download or purchase, and Unity shall notify each Customer that the Customer's use of that Asset is subject to the terms and conditions of Providers EULA. In the event that the Provider does not furnish Providers own EULA to Unity, Provider acknowledges and agrees that each Customer's use of all Assets shall be subject to Unity's standard EULA (Appendix 1).


6.8

Provider hereby acknowledges that the applicable EULA for each of the Assets is solely between Provider and the Customer and conforms to applicable law, and Unity shall not be responsible for, and shall not have any liability whatsoever under, any EULA or any breach by Provider or any Customer of any of the terms and conditions of any EULA.


6.9

Provider represents and warrants that Provider has all intellectual property rights, including all necessary patent, trademark, trade secret, copyright or other proprietary rights, in and to Provider's Assets. If Provider uses third-party materials, Provider represents and warrants that Provider has the right to distribute the third-party material in the Assets. Provider agrees that Provider will not submit material to Unity Asset Store that is copyrighted, protected by trade secret or otherwise subject to third party proprietary rights, including patent, privacy and publicity rights, unless Provider is the owner of such rights or has permission from the rightful owner to submit the material.

 

7.

Brand Features and Publicity

7.1

Each Party shall own all right, title and interest, including without limitation all intellectual property rights, relating to its Brand Features. Except to the limited extent expressly provided in this Agreement, neither Party grants, nor shall the other Party acquire, any right, title or interest (including, without limitation, any implied license) in or to any Brand Features of the other Party.


7.2

Subject to the terms and conditions of this Agreement, Provider grants to Unity and its affiliates a limited, non-exclusive license during the term of this Agreement to display Provider's Brand Features, submitted by Provider to Unity, for use solely online or on mobile devices and in either case solely in connection with the distribution and sale of Provider's Assets through the Unity Asset Store, or to otherwise fulfill its obligations under this Agreement.


7.3

If Provider discontinues the distribution of specific Assets on the Unity Asset Store, Unity will, after a reasonable amount of time from receipt of notice, cease use of the discontinued Assets' Brand Features, except as necessary to allow Unity to effectuate Section .


7.4

Nothing in this Agreement gives Provider a right to use any of Unity's Brand Features.


7.5

Publicity

(まだ)

7.5.1

In addition to the license granted in Sections and above, for purposes of marketing the presence, distribution and sale of the Provider's Asset in the Unity Asset Store, Unity and its affiliates may include Provider's Brand Features, submitted by Provider to Unity:


(i) within the Unity Asset Store and in any Unity-owned online or mobile properties;


(ii) in online or mobile communications outside the Unity Asset Store when mentioned along with other Assets from the Unity Asset Store;


(iii) when making announcements of the availability of the Asset online or on mobile devices;


(iv) in presentations; and


(v) in customer lists which appear either online or on mobile devices (which includes, without limitation, customer lists posted on Unity websites, including the Unity Asset Store).

7.5.2

If Provider discontinues the distribution of specific Assets on the Unity Asset Store, Unity will, after a reasonable amount of time from receipt of notice, cease use of the discontinued Assets' Brand Features for such marketing purposes.

 

8.

Asset Takedowns

(まだ)

8.1

Provider's Takedowns

8.1.1

Provider may remove Provider's Assets from future distribution via the Unity Asset Store at any time, but Provider must comply with this Agreement and the Payment Processor's terms of service for any Assets distributed through the Unity Asset Store, including but not limited to refund requirements. Removing Provider's Assets from future distribution via the Unity Asset Store does not (a) affect the license rights of Customers who have previously purchased or downloaded Provider's Assets, (b) remove Provider's Assets from Customers' equipment or from any part of the Unity Asset Store where previously purchased or downloaded Assets are stored on behalf of Customers, or © change Provider's obligation to deliver or support Assets or services that have been previously purchased or downloaded by Customers. Notwithstanding the foregoing, in no event will Unity maintain on any portion of the Unity Asset Store (including, without limitation, the part of the Unity Asset Store where previously purchased or downloaded Assets are stored on behalf of Customers) any Asset that Provider has removed from the Unity Asset Store and provided written notice to Unity that such removal was due to (i) an allegation of infringement, or actual infringement, of any copyright, trademark, trade secret, trade dress, patent or other intellectual property right of any person, (ii) an allegation of defamation or actual defamation, (iii) an allegation of violation, or actual violation, of any third party's right of publicity or privacy, or (iv) an allegation or determination that such Asset does not comply with applicable law.

8.1.2

If Provider removes an Asset from the Unity Asset Store pursuant to clauses (i), (ii), (iii) or (iv) of Section , and a Customer purchased such Asset within a year before the date of takedown, at Unity's request, Provider must refund to the affected Customer all amounts paid by such Customer for such affected Asset, including the 30 (thirty) per cent that Unity has received, cf. Section above. Alternatively, Unity may elect to deduct and withhold such refund amount from any current Customer balance.

8.2

Unity Takedowns

8.2.1

While Unity does not undertake any legal obligation to monitor the Assets or their content, Unity reserves the right to do so, and, if Unity is notified by Provider or otherwise becomes aware and determines in its sole discretion that an Asset or any portion thereof or Provider's Brand Features; (a) violates the intellectual property rights or any other rights of any third party; (b) violates any applicable law or is subject to an injunction; © is pornographic, obscene or otherwise violates Unity's hosting policies or other terms of service as may be updated by Unity from time to time in its sole discretion; (d) is being distributed by Provider improperly; (e) may create liability for Unity; (f) is deemed by Unity to have a virus or is deemed to be malware, spyware or have an adverse impact on Unity; (g) violates the terms of this Agreement or the Asset Store Guidelines; or (h) the display of the Asset is impacting the integrity of Unity servers (i.e., Customers are unable to access such content or otherwise experience difficulty), Unity may demand that Provider fixes the Asset. In addition Unity shall itself be entitled to edit and make changes in the Asset. Finally Unity shall be entitled to remove the Asset from the Unity Asset Store immediately, or reclassify the Asset at its sole discretion and without any liability. Unity reserves the right to suspend and/or bar any Provider from the Unity Asset Store at its sole discretion.

8.2.2

In the event that Provider's Assets are removed by Unity because it is defective, malicious, infringes intellectual property rights of another person, defames, violates a third party's right of publicity or privacy, or does not comply with applicable law, and a Customer purchased such Asset within a year before the date of takedown: (i) Provider must refund to Unity, a sum corresponding to the full purchase price that the Customer has paid for the Asset in question and Unity will then repay the full price to the Customer, and (ii) Unity may, at its sole discretion, withhold from Provider's future sales the amount in subsection (i) immediately above.

8.2.3

In addition to the reasons specified in Section Unity may remove Assets from the Unity Asset Store at Unity's sole discretion after providing 30 days’ notice.

 

9.

Provider's Upgrades of Assets

9.1

Provider agrees that Provider will, at no cost to Customers and Unity, supply via the Unity Asset Store any upgrades or otherwise updated versions of all Assets that a Customer has acquired from the Unity Asset Store. For the avoidance of doubt, this does also apply to any Asset that has been distributed for free via the Unity Asset Store.

プロバイダは無償で、Unityアセットストア経由で、ユーザーが購入済みであるアセットのアップデートに対応するものとする。

誤解をさける為に明記すると、この条件は、無料のアセットに対しても適応されるものとする。

 

10.

Privacy, Information and Confidentiality

(まだ)

10.1

In order to continually innovate and improve the Unity Asset Store, Unity may collect certain usage statistics from the Unity Asset Store, including but not limited to, information on how the Unity Asset Store is being used.


10.2

The data collected is examined in the aggregate to improve the Unity Asset Store for Customers and Providers and is maintained in accordance with Unity's privacy policy in force at any time. To ensure the improvement of Assets, Unity may, at its discretion, through provide limited aggregated, anonymous data to the Provider.

 

11.

Terminating this Agreement

(まだ)

11.1

This Agreement will continue to apply until terminated by either Provider or Unity as set out below.


11.2

Provider may terminate this Agreement by ceasing use of the Unity Asset Store and removing any Assets from the Unity Asset Store.


11.3

Unity may at any time, terminate this Agreement if: (A) Provider breaches the Agreement; (B) Unity is required to do so by law; or © Unity decides to no longer provide the Unity Asset Store.


11.4

Upon termination, all of the legal rights, obligations and liabilities that Provider and Unity have benefited from, been subject to (or which have accrued over time whilst the Agreement has been in force) or which are expressed to continue indefinitely shall be unaffected by this cessation.Either party may terminate this Agreement at any time by providing notice to the other party.

 

12.

Disclaimer of Warranties

12.1

PROVIDER EXPRESSLY UNDERSTANDS AND AGREES THAT PROVIDER'S USE OF THE ASSET STORE IS AT PROVIDER'S SOLE RISK AND THAT THE UNITY ASSET STORE IS PROVIDED "AS IS" AND "AS AVAILABLE" WITHOUT WARRANTY OF ANY KIND.

12.2

PROVIDER'S USE OF THE UNITY ASSET STORE AND ANY MATERIAL DOWNLOADED OR OTHERWISE OBTAINED THROUGH THE USE OF THE UNITY ASSET STORE IS AT PROVIDERR OWN DISCRETION AND RISK AND PROVIDER IS SOLELY RESPONSIBLE FOR ANY DAMAGE TO PROVIDER'S COMPUTER SYSTEM OR OTHER EQUIPMENT OR LOSS OF DATA THAT RESULTS FROM SUCH USE.

12.3

PROVIDER EXPRESSLY UNDERSTANDS AND AGREES THAT UNITY IS NOT RESPONSIBLE AND LIABLE FOR ANY UNAUTHORIZED USE OF PROVIDERS ASSETS OUTSIDE THE UNITY ASSET STORE INCLUDING – WITHOUT LIMITATION – ANY SALE OR OTHER KIND OF DISTRIBUTION OF ASSETS FROM PIRATE WEB SITES OR THE LIKE. UNITY EXPRESSLY DISCLAIMS ANY SUCH LIABILITY.

12.4

UNITY FURTHER EXPRESSLY DISCLAIMS ALL WARRANTIES AND CONDITIONS OF ANY KIND, WHETHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES AND CONDITIONS OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON- INFRINGEMENT.

 

13.

Limitation of Liability

13.1

PROVIDER EXPRESSLY UNDERSTANDS AND AGREES THAT UNITY AND ITS SUBSIDIARIES, HOLDING COMPANIES AND OTHER AFFILIATES TOTAL LIABILITY FROM ALL CAUSES OF ACTION AND UNDER ALL THEORIES OF LIABILITY UNDER THESE TERMS WILL BE LIMITED TO THE AMOUNTS PAID TO PROVIDER BY UNITY IN THE PAST SIX MONTHS FOR THE ASSETS RELATING TO THE DISPUTE. IN NO EVENT WILL UNITY OR ITS SUBSIDIARIES, HOLDING COMPANIES AND OTHER AFFILIATES SHALL BE LIABLE TO YOU FOR ANY SPECIAL, INCIDENTAL, EXEMPLARY, PUNITIVE OR CONSEQUENTIAL DAMAGES (INCLUDING LOSS OF DATA, BUSINESS, PROFITS OR ABILITY TO EXECUTE) OR FOR THE COST OF PROCURING SUBSTITUTE PRODUCTS ARISING OUT OF OR IN CONNECTION WITH THESE TERMS OR YOUR USE OF THE ASSET STORE OR ANY ASSETS DOWNLOADED OR OTHERWISE OBTAINED FROM THE UNITY ASSET STORE, WHETHER SUCH LIABILITY ARISES FROM ANY CLAIM BASED UPON CONTRACT, WARRANTY, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, AND WHETHER OR NOT UNITY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH LOSS OR DAMAGE. THE FOREGOING LIMITATIONS WILL SURVIVE AND APPLY EVEN IF ANY LIMITED REMEDY SPECIFIED IN THIS AGREEMENT IS FOUND TO HAVE FAILED OF ITS ESSENTIAL PURPOSE.

 

14.

Indemnifications

14.1

To the maximum extent permitted by law, Provider agrees to defend, indemnify and hold harmless Unity, its affiliates and their respective directors, officers, employees and agents, from and against any and all third party claims, actions, suits or proceedings, as well as any and all losses, liabilities, damages, costs and expenses (including reasonable attorneys fees) arising out of or accruing from (a) Provider's use of the Unity Asset Store in violation of this Agreement, and (b) Provider's Assets that infringe any copyright, trademark, trade secret, trade dress, patent or other intellectual property right of any person or defame any person or violate their rights of publicity or privacy.

14.2

To the maximum extent permitted by law, Provider agrees to defend, indemnify and hold harmless the applicable Payment Processors (which may include Unity and/or third parties) and the Payment Processors' affiliates, directors, officers, employees and agents from and against any and all third party claims, actions, suits or proceedings, as well as any and all losses, liabilities, damages, costs and expenses (including reasonable attorneys fees) arising out of or accruing from taxes related to Provider's distribution of Assets distributed via the Unity Asset Store.

 

15.

Changes to the Agreement

15.1

Unity may make changes to this Agreement at any time by posting a revised Agreement in Unity Asset Store.

16.

General Legal Terms

16.1

This Agreement constitutes the whole legal agreement between Provider and Unity and governs Provider's use of the Unity Asset Store, and completely replaces any prior agreements between Provider and Unity in relation to the Unity Asset Store.

16.2

Provider agrees that if Unity does not exercise or enforce any legal right or remedy which is contained in this Agreement (or which Unity has the benefit of under any applicable law), this will not be taken to be a formal waiver of Unity's rights and that those rights or remedies will still be available to Unity.

16.3

If any court of law, having the jurisdiction to decide on this matter, rules that any provision of this Agreement is invalid, then that provision will be removed from this Agreement without affecting the rest of this Agreement. The remaining provisions of this Agreement will continue to be valid and enforceable.

16.4

Provider acknowledges and agrees that each member of the group of companies to which Unity belongs shall be third party beneficiaries to this Agreement and that such other companies shall be entitled to directly enforce, and rely upon, any provision of this Agreement that confers a benefit on (or rights in favor of) them. Other than this, no other person or company shall be third party beneficiaries to this Agreement.

16.5

EXPORT RESTRICTIONS. ASSETS ON THE ASSET STORE MAY BE SUBJECT TO EXPORT LAWS AND REGULATIONS. PROVIDER MUST COMPLY WITH ALL DOMESTIC AND INTERNATIONAL EXPORT LAWS AND REGULATIONS THAT APPLY TO PROVIDER'S DISTRIBUTION OR USE OF ASSETS. THESE LAWS INCLUDE RESTRICTIONS ON DESTINATIONS AND CUSTOMERS.

16.6

The rights granted in this Agreement may not be assigned or transferred by Provider without the prior written approval of Unity and Provider shall not be permitted to delegate its responsibilities or obligations under this Agreement without the prior written approval of Unity. The rights granted in this Agreement may be assigned or transferred by Unity without Provider's prior approval. In addition Unity shall be permitted to delegate its responsibilities or obligations under this Agreement without Provider's approval.

16.7

This Agreement, and Provider's relationship with Unity under this Agreement, shall be governed by the laws of Denmark without regard to its conflict of laws provisions. Any dispute arising out of or in connection with this Agreement, including any disputes regarding the existence, validity or termination thereof, shall be settled by simplified arbitration arranged by The Danish Institute of Arbitration in accordance with the rules of simplified arbitration procedure adopted by The Danish Institute of Arbitration and in force at the time when such proceedings are commenced. Notwithstanding this, Provider agrees that Unity shall still be allowed to apply for injunctive remedies (or an equivalent type of urgent legal relief) in any jurisdiction.

16.8

The obligations in Sections 6, 7.1 (solely as necessary to permit Unity to effectuate Section 4.8), 8, 12, 13, 14, and 16 will survive any expiration or termination of this Agreement.


APPENDIX 1 - ASSET STORE END USER LICENSE AGREEMENT

1.

Parties to the Agreement/ The Subject Matter of the Agreement:

1.1

This Unity-EULA (hereinafter referred to as “EULA”) is a non-exclusive, leg- ally binding end user license agreement between any individual or a single entity (“END-USER”) that acquires an Asset from the Unity Asset Store and either (i) Unity Technologies APS (company no. 30 71 99 13), Livjægergade 17,1, 2100 Copenhagen Ø, Denmark (“Licensor” or "Unity"), or as the case may be (ii) any third party (“Provider”) that distributes its Assets from the Unity Asset Store. Consequently, this EULA shall apply regardless of wheth- er a purchased Asset is produced by Unity or by a Provider ("Licensor"). T his EULA is therefore a non-exclusive, legally binding end user license agree- ment as the case may be between either (i) Unity and END-User (in which case the term "Licensor" shall refer to Unity), or (ii) Provider and End User (in which case the term "Licensor" shall refer to Provider).

1.2

In the event that any Provider distributes Assets through the Unity Asset Store, then such Provider shall be allowed to furnish it’s own Provider-EULA ("Provider-EULA") that shall be applicable only to such Assets. In this case END-USER must accept such Provider-EULA by clicking where this option is made available on the Unity Asset Store. In the event that the Provider does not furnish a Provider-EULA for any Asset to Unity, then such Assets will also (mutatis mutandis) be subject to this EULA. In this event this EULA is a non-exclusive, legally binding end user license agreement between Provider and End User and in this event the term "Licensor" shall refer to Provider.

1.3

In the event of any discrepancies between this EULA and any Pro- vider-EULA, the terms of this EULA that are or are intended to safeguard Unity's interests shall prevail over the terms of such Provider-EULA and be enforceable between END-USER and Unity.

1.4

By installing, copying, accessing, downloading or otherwise using the Assets, End User agrees to be bound the provisions of this EULA and the Provider- EULA as the case may be. All definitions of the Terms shall also apply in this EULA unless the context clearly provides for a different understanding.

1.5

The subject matter of this EULA is the licensing to END-USER of any Asset acquired by End User from the Unity Asset Store. The Assets are licensed, not sold.

1.6

END USER hereby acknowledges that in the event it acquires an ASSET which in the Unity Asset Store is marked as an Asset which is distributed by Provider (as opposed to Unity), then Provider shall be considered as Li- censor of such Asset and, consequently, only Provider (as opposed to Unity) shall be responsible for any liability whatsoever under, any EULA or any breach by Provider, including (without limitation) liability for infringement of any intellectual property rights, irrespective of the fact that payment takes place to Unity.


2.

END-USER's Rights and Obligations

2.1

END-USER may use the licensed Assets only for their intended purpose.

2.2

Licensor grants to the END-USER a non-exclusive, worldwide, and perpetu- al license to the Asset to integrate Assets only as incorporated and embed- ded components of electronic games and interactive media and distribute such electronic game and interactive media. END-USER may otherwise not reproduce, distribute, sublicense, rent, lease or lend the Assets. It is emphasized that the END-USERS shall not be entitled to distribute or transfer in any way (including, without, limitation by way of sublicense) the Assets in any other way than as integrated components of electronic games and inter- active media. Without limitation of the foregoing it is emphasized that END- USER shall not be entitled to share the costs related to purchasing an Asset and then let any third party that has contributed to such purchase use such Asset (forum pooling).

2.3

EXCEPT FOR EDITOR EXTENSION ASSETS, END-USER is granted a li- cense to install and use Assets on an unlimited number of PCs provided that these PCs are either all (i) physically located at a single physical location ("Site") belonging to END-USER, or (ii) laptops belonging to END-USER which have been made available by END-USER to its employees that are employed at the same Site provided all such PCs and laptops have appropri- ately licensed Unity software installed. Consequently, any Asset may only be used at particular Site or on laptops assigned to END-USER's employees employed at the same Site and may only be moved to another Site subject to prior written approval from Licensor. THIS CLAUSE 2.3 DOES NOT APPLY TO ASSETS THAT IN THE UNITY ASSET STORE ARE CATEGORIZED UNDER THE HEADING "EDITOR EXTENSIONS", cf. clause 2.4 below.

2.4

Editor Extensions: END-USER is granted a license to install and use any As- sets which are categorized in the Asset Store as "Editor Extensions" only on one (1) PC. For the avoidance of doubt, Editor Extension Assets are licensed per “seat” may not be shared or used concurrently on different PCs.

2.5

END-USER shall pay for the license to the Assets in accordance with the payment process provided in the Asset Store.

3.

Licensor’s Rights and Obligations

3.1

Licensor shall render support services to END-USER only in the event a spe- cial agreement to this effect has been entered into.

4.

Termination

4.1

Without prejudice to any other rights, Licensor may terminate this EULA if END-USER fails to comply with the terms and conditions of this EULA and the Terms.

4.2

END-USER may terminate END-USER’s license at any time.

4.3

In the event that Unity at its discretion or as a result of a decision made by any competent court or authority makes a refund to END-USER of the fees paid for any Asset, then this EULA shall terminate for such Asset.

4.4

In the event of termination of this EULA, all license rights granted herein terminate and END-USER shall immediately destroy any and all copies of the Assets contained on any type of media under the control of END-USER.

5.

Duplication Rights/Back Up Copy

5.1

END-USER may not make copies of the Assets, except and only to the extent that such activity is expressly permitted under mandatory statutory applicable law. In addition Licensor acknowledges that copies of the Assets may be made when the Assets have been integrated as parts of electronic games and interactive media, cf. Section 2.3 above.

5.2

After installation of one copy of the Asset pursuant to this EULA, END USER may keep the original copy of the Asset solely for back up or archival purposes.

6.

Reverse Engineering, Decompilation, and Disassembly

6.1

END USER may not reverse engineer, decompile, or disassemble the Assets, except and only to the extent that such activity is expressly permitted under mandatory statutory applicable law.

7.

Trademarks

7.1

This EULA does not grant END-USER any rights in connection with any trademarks or service marks of Licensor, Provider or Licensor's other sup- pliers.

8.

Upgrades and Support

8.1

Assets identified as upgrades replace and/or supplement the licensed Assets.

8.2

Licens or may at its own discretion from time to time provide upgrades of the Assets to END USER without requesting further payment. Irrespective hereof END-USER is only entitled to licenses to upgrades if END-USER has entered into an Upgrade Agreement with Licensor. END-USER may use the upgraded Assets only in accordance with the terms of this EULA.

8.3

END-USER is only entitled to support if END-USER has entered into a Support Agreement with Licensor.


9.

Copyright

9.1

The Assets are protected by copyright laws and international copyright treat - ies, as well as other intellectual property laws and treaties.

9.2

All title and intellectual property rights in and to the Assets (including but not limited to any software, images, photographs, animations, graphics, 3D graphics, video, audio, music, text, tutorials, and “applets” incorporated into the Assets), the accompanying printed materials, and any copies of the As- sets are owned by Licensor. All rights not expressly granted are reserved by Licensor.


10.

Disclaimer of Warranties

10.1

END-USER UNDERSTANDS AND ACCEPTS THAT PRIOR TO PLA- CING ANY ASSET ON THE UNITY ASSET STORE, UNITY DOES NOT UN- DERTAKE ANY LEGAL OBLIGATION TO MONITOR, PRE-SCREEN, RE- VIEW, FLAG, FILTER, MODIFY, REFUSE OR REMOVE ANY ASSET OR THEIR CONTENT FROM THE UNITY ASSET STORE. CONSEQUENTLY, END-USER EXPRESSLY UNDERSTANDS AND AGREES THAT ITS USE OF THE ASSETS IS AT END-USER'S SOLE RISK AND THAT THE ASSETS ARE PROVIDED “AS IS” AND “AS AVAILABLE” WITHOUT WARRANTY OF ANY KIND, TO THE MAXIMUM EXTENT PERMITTED BY APPLIC- ABLE LAW. IN PARTICULAR, LICENSOR, ITS SUBSIDIARIES, HOLDING COMPANIES AND AFFILIATES, AND ITS LICENSORS DO NOT REPRESENT OR WARRANT TO END-USER THAT:


(A) END-USER'S USE OF THE ASSETS WILL MEET END-USER'S REQUIREMENTS,


(B) END-USER'S USE OF THE ASSETS WILL BE UNINTERRUPTED, TIMELY, SECURE OR FREE FROM ERROR,


(C) ANY IN©MATION OBTAINED BY END-USER AS A RESULT OF END-USER'S USE OF THE ASSETS WILL BE ACCURATE OR RELIABLE, AND


(D) THAT DEFECTS IN THE OPERATION OR FUNCTIONALITY OF ANY SOFTWARE PROVIDED TO END-USER AS PART OF THE ASSETS WILL BE CORRECTED.

10.2

END-USER'S USE OF ANY ASSETS IS AT END-USER'S OWN DIS- CRETION AND RISK AND END-USER IS SOLELY RESPONSIBLE FOR ANY DAMAGE TO END-USER'S COMPUTER SYSTEM, OR OTHER DEVICE, OR LOSS OF DATA THAT RESULTS FROM SUCH USE.


10.3

TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, LI- CENSOR FURTHER EXPRESSLY DISCLAIMS ALL WARRANTIES TERMS OR CONDITIONS OF ANY KIND, WHETHER EXPRESS OR IMPLIED, IN- CLUDING, BUT NOT LIMITED TO ANY IMPLIED WARRANTIES TERMS AND CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT, WITH RESPECT TO ANY ASSETS.


10.4

NONE OF THE ASSETS ARE INTENDED FOR USE IN THE OPERATION OF NUCLEAR FACILITIES, LIFE SUPPORT SYSTEMS, EMERGENCY COMMUNICATIONS, AIRCRAFT NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL SYSTEMS, OR ANY OTHER SUCH ACTIVITIES IN WHICH CASE THE FAILURE OF THE ASSETS COULD LEAD TO DEATH, PERSONAL INJURY, OR SEVERE PHYSICAL OR EN- VIRONMENTAL DAMAGE.

11.

Limitation of Liability

11.1

LICENSOR AND ITS SUBSIDIARIES, HOLDING COMPANIES AND OTHER AFFILIATES TOTAL LIABILITY TO END-USER FROM ALL CAUSES OF ACTION AND UNDER ALL THEORIES OF LIABILITY UNDER THESE TERMS WILL BE LIMITED TO THE AMOUNTS PAID TO END-USER BY END-USER IN THE PAST SIX MONTHS FOR THE ASSETS RELATING TO THE DISPUTE. IN NO EVENT WILL LICENSOR OR ITS SUBSIDIARIES, HOLDING COMPANIES AND OTHER AFFILIATES SHALL BE LIABLE TO END-USER FOR ANY SPECIAL, INCIDENTAL, EXEMPLARY, PUNITIVE OR CONSEQUENTIAL DAMAGES (INCLUDING LOSS OF DATA, BUSINESS, PROFITS OR ABILITY TO EXECUTE) OR FOR THE COST OF PROCURING SUBSTITUTE PRODUCTS ARISING OUT OF OR IN CONNECTION WITH THESE TERMS OR YOUR USE OF THE ASSET STORE OR ANY ASSETS DOWNLOADED OR OTHERWISE OBTAINED FROM THE UNITY ASSET STORE, WHETHER SUCH LIABILITY ARISES FROM ANY CLAIM BASED UPON CONTRACT, WARRANTY, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, AND WHETHER OR NOT LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH LOSS OR DAMAGE. THE FOREGOING LIMITATIONS WILL SURVIVE AND APPLY EVEN IF ANY LIMITED REMEDY SPECIFIED IN THIS AGREEMENT IS FOUND TO HAVE FAILED OF ITS ESSENTIAL PURPOSE.

11.2

END-USER EXPRESSLY UNDERSTAND AND AGREE THAT LICENSOR, ITS SUBSIDIARIES, HOLDING COMPANIES AND AFFILIATES, AND ITS LI- CENSORS SHALL NOT BE LIABLE TO END-USER FOR ANY LOSS OR DAMAGE WHICH MAY BE INCURRED BY END-USER, INCLUDING BUT NOT LIMITED TO LOSS OR DAMAGE AS A RESULT OF:


(I) ANY RELIANCE PLACED BY END-USER ON THE COMPLETENESS, ACCURACY OR EXISTENCE OF ANY ADVERTISING, OR AS A RESULT OF ANY RELATIONSHIP OR TRANSACTION BETWEEN END-USER AND LICENSOR OR ANY, DEVELOPER, ADVERTISER OR SPONSOR WHOSE ADVERTISING APPEARS IN THE ASSETS OR ON THE UNITY ASSET STORE;


(II) ANY CHANGES WHICH LICENSOR MAY MAKE TO THE ASSETS OR ON THE UNITY ASSET STORE, OR FOR ANY PERMANENT OR TEMPORARY CESSATION IN THE PROVISION OF THE UNITY ASSET STORE OR THE ASSETS (OR ANY FEATURES WITHIN THE ASSETS);


(III) THE DELETION OF, CORRUPTION OF, OR FAILURE TO STORE, ANY CONTENT AND OTHER COMMUNICATIONS DATA MAINTAINED OR TRANSMITTED BY OR THROUGH END-USER'S USE OF THE ASSETS;


(IV) END-USER'S FAILURE TO PROVIDE UNITY WITH ACCURATE ACCOUNT INFORMATION;

11.3

NOTHING IN THE TERMS EXCLUDES THE LIABILITY FOR LICENSOR, ITS SUBSIDIARIES OR AFFILIATES FOR: (I) DEATH AND PERSONAL IN- JURY CAUSED BY NEGLIGENCE; (II) FRAUDULENT MISREPRESENTA- TION; OR (III) ANY OTHER LIABILITY WHICH CANNOT BE LIMITED BY APPLICABLE LAW.

12.

Export Restrictions

12.1

Assets available on the Unity Asset Store may be subject to laws, adminis- trative regulations and executive orders of those authorities responsible according to any applicable laws relating to the control of imports and ex- ports of the Assets (“Export Laws”). You agree to comply with all applic- able Export Laws and you shall not export or re-export directly or indir- ectly (including via remote access) any part of the Assets to any country to which a license is required under the Export Laws without first obtaining a license.

13.

Venue and Applicable Law

13.1

This EULA and END-USER's relationship with Licensor under this EULA, shall be governed by the laws of Denmark without regard to its con- flict of laws provisions. Any dispute arising out of or in connection with this Agreement, including any disputes regarding the existence, validity or termination thereof, shall be settled by simplified arbitration arranged by The Danish Institute of Arbitration in accordance with the rules of simplified arbitration procedure adopted by The Danish Institute of Arbitration and in force at the time when such proceedings are commenced. Notwithstanding this, Provider agrees that Licensor shall still be allowed to apply for injunct- ive remedies (or an equivalent type of urgent legal relief) in any jurisdiction.

 

wrote 2013/06/13 02:31:23

Unityで、彼の勇姿のその果てをグラフ化、、


概要

Unityでの特定のパラメータを、Debug.Log → ブラウザでグラフとして表示、というものを作ってみた。

https://vimeo.com/67981607


SublimeText依存。



期待している用途

ゲームの流れの中で、特定のタイミングでの特定のパラメータだけを抜き出してグラフにしたい。

例えばキャラの速度の最速値とか、クリアの最短値とか。

特定の条件を満たした時に「だけ」記録されるポイントから作られたグラフが見たかった。


で、そのへんのピックアップ+グラフ描画までを最短でする仕組みを作ってみた。



用意するもの

おなじみ 3rd Person Controller さん

スクリーンショット 2013-06-09 20.04.54.png

あれ、、なんかかっこいい、、



UnitySublimeSocketAsset

UnityとSublimeTextとかを繋ぐアセット。

(今度加筆)


このアセットから直接利用することができる。

そのほか、最新のSublimeSocket にToolとして入れたので、Unity以外からも利用可能。



こんなコード

using UnityEngine;

using System.Collections;


public class NewBehaviourScript : MonoBehaviour {


GameObject the3dPlayer;

// Use this for initialization

void Start () {

the3dPlayer = GameObject.Find("3rd Person Controller");

}

// Update is called once per frame

void Update () {

Debug.Log("G:"+the3dPlayer.transform.position.y);

}

}

カメラとかにくっつけてActiveな状態にしておく。

すると、

G:ってくっつけたログのパラメータが、ブラウザのグラフに描画される。



ブラウザ

WebSocketと、flot(http://www.flotcharts.org)が動けば何でも良いと思います。

WebSocketでのシグナルを受けて描画するようにセットしておきます。



動かすと

いけっ! 3rd Person Controller!!

スクリーンショット 2013-06-09 20.07.10.png

登場の瞬間、まず小さく落下してから元気に走り出す彼。 微妙な上下動が不快。

1__#$!@%!#__スクリーンショット 2013-06-09 20.07.10.png

ジャンプするとグラフにも反応が! 5.5ちょいくらいまで飛んでるみたいですね! 単位なんだろう。

スクリーンショット 2013-06-09 20.07.16.png

そして彼方に向かって跳躍、、!

スクリーンショット 2013-06-09 20.07.44.png

ぐんぐん下がる右端。 グラフがタテに圧縮されていく。

スクリーンショット 2013-06-09 20.07.51.png


スクリーンショット 2013-06-09 20.07.56.png

彼は犠牲になったのだ。 晩ご飯何食べよう。



連動の仕組み

Unityからは、UnitySublimeSocketAssetを介して、ブラウザへと

「ログ文が発生したタイミングで」値を送付している。


今回はUpdate文の内部から

the3dPlayer.transform.position.y

を送ってみたけれど、だいたいリアルタイムっぽくグラフが追加された。


FixedUpdate内から実行しても特に遅延無かったので、OKということで。



Unity以外から使ってみる

SublimeSocket 1.1.3以降に加えておいたので、SublimeSocket/tool/graph からhtml開いて、WebSocketで点を送ると到着順にグラフ化される。

アセットのWindows版がでてからしっかり書く。


wrote 2013/06/09 20:02:26

Unityで曲線状にオブジェクトを動かすSuperSplinesを使ってみた


概要

Splineに乗って動く、みたいなツールを探していた。

動作のデザインをカウンタで制御、とか、面倒なんだけど、動作を式化するプログラムを書くのも面倒だったので探してみたら

あったあった。


SuperSplines

http://u3d.as/content/evoluo-technologies/super-splines/2kK


で、そのAPI

http://www.super-splines.de/documentation/example3.html


本家紹介ムービー(あるんじゃね?って言われて探したらあった、、クソっ先に知っていれば、、)

http://www.youtube.com/watch?v=AAfJDQggRvA


やりたい事

移動を表す関数 Aに対して、

A(0)とか A(0.4)とか A(1) とか入れると、想定されたライン上の特定の位置に居るような式が欲しかったのよさ。

具体的には、


transform.positon = A(0).transform;//位置

transform.rotation = A(0).rotation;//傾きとか回転


とか。


任意の数値について、「特定のタイミングの値」での、ある線上のパラメータを返す、みたいなの。

線って書いたけど、テキトーな1,2次曲線とか直線、円ならまあ式が単純だし自作してもサクッと出来るし楽なんだと思うのですが、


線に沿って人を歩かせて、向きとか傾きを出す、みたいなのを作るとしんどいわけで。


上記式を提供してくれるAssetをちょっと探していた。

そこでSuperSpinesですよ。


購入

25$のほうを買いました。

Pro版というか上位版もあるんだけど、見てると差が「ソースコード入ってまっせ!」だったので、

うん、今は使えれば良いからいいや!



使い方

適当にCubeを用意。SuperSplinesはインストール済み。

スクリーンショット 2013-06-07 9.43.38.png

Splineを作成

GameObject > CreateOther > Spline > HermiteとかBezierとか曲線のタイプ。

スクリーンショット 2013-06-07 9.44.42.pngスクリーンショット 2013-06-07 9.44.45.pngスクリーンショット 2013-06-07 10.45.41.png

で、こんなのが出る。 4つの点から構成されたSpline。これはBSpline。

始点と終点を結ぶ線が、間の点に引っ張られるような感じで補完される。

スクリーンショット 2013-06-07 9.50.53.png

4つの点を勝手にキレイな曲線で結んでくれている。あとは、適当に編集して遊ぶ。

AutoCloseにチェックを入れると、線が閉じて輪になる。


(下のは2、3回クリックすると再生できるんじゃないだろうか。きっと)

trimed2.mp4




Cubeを動かす

で、これをオブジェクトに対応させるには、適当なScriptを用意してその中でこんな感じに書けば良い。


SplineMove.cs

using UnityEngine;

using System.Collections;


using SplineUtilities;


public class SplineMove : MonoBehaviour {


//Splineオブジェクト

public Spline spline;


  //移動カウンタ

  float counter;

  

  float passedTime;


// Update is called once per frame

void Update () {

passedTime = (counter % 101) * 0.01f;


//passedTimeの撮り得る値は0から1.00

   float clampedParam = SplineUtils.WrapValue(passedTime, 0f, 1f, WrapMode.Clamp);


    //表示上の変形を適応する

    transform.position = spline.GetPositionOnSpline( clampedParam );

    transform.rotation = spline.GetOrientationOnSpline( clampedParam );

}


void FixedUpdate () {

counter ++; 

}

}


こいつをCubeにアタッチ。

スクリーンショット 2013-06-07 11.28.04.png

で、Splineのところに、先ほど作成したNew Spline をアタッチ。

bassui.png

動かすと、こんな感じ。

ちなみにこれはBSplineではなくHermite。すべての点を通る曲線を補完している。

(下のも2、3回クリックすると再生できるんじゃないだろうか。きっと)

trimed3.mp4


いやあ、便利。

特定のチェックポイントを通る、とかが簡単に作れるね!



wrote 2013/06/07 9:29:00

KyokoさんかわいいよKyokoさん


概要

Macで日本語ナレーションの入ったムービー作るの試してたら渡りに船なアプリを紹介され、

調子に乗って適当なものを作りました。


参考になったサイト

「おすすめのMac無料アプリ、50個集めてみました。初心者から上級者までおすすめです。」

http://macwin.org/mac/2013-freeapp50/

欲しかった道具はだいたいこの中に入ってました。


道具

動画編集

iMovie(無言)


読み上げ

TextRecorder

スクリーンショット 2013-06-05 23.26.01.png

これとKyokoの組み合わせが凄くよいです。


sayでKyokoさん使ってたときは「あーこりゃ、、うん、、」って思ってたんだけど、

インターフェース変わると使い物になるんだなーという印象。



Tips for TextRecorder

こんなインターフェースなんですけど

スクリーンショット 2013-06-05 23.30.15.png


単語の間の「ため」を、英語なら,(カンマ)で0.2秒、.(ドット)で0.5秒くらい、な感じで調節できました。


で、日本語なら, 。 がこれに対応する感じ。


で、作ったもの

UnitySublimeSocketAssetのCM

https://vimeo.com/67730596


wrote 2013/06/05 23:25:40

いろんな通信を相互に繋ぐMacアプリ SocketRoundabout

スクリーンショット 2013-05-30 11.55.32.png

概要

WebSocketを受けて、NSDistributedNotificationへと流す、とかがやりたくて作ったもの。

簡易のWebSocketサーバとかになる。


WebSocketサーバ → 別のWebSocketクライアント → 別のWebSocketサーバ、、とか接続する事が可能。

https://github.com/sassembla/SocketRoundabout-WS-NSDistNotif


設定ファイル

こんな感じの事を書いた.sr拡張子のテキストファイルを用意すると、設定をこなしながら起動する。


//1 WebSocketのOperationをセットする

id:roundaboutTest0_2013/05/16_13:40:13 type:0 destination:ws://127.0.0.1:8823 option:websocketas:client

id:roundaboutTest1_2013/05/16_13:40:13 type:1 destination:testNotif


//接続待ち

//connent

connect:roundaboutTest1_2013/05/16_13:40:13 to:roundaboutTest0_2013/05/16_13:40:13


//transfer

trans:roundaboutTest1_2013/05/16_13:40:13 to:roundaboutTest0_2013/05/16_13:40:13 prefix:TEST_PREFIX suffix:TEST_SUFFIX


たぶんREADME.mdみたほうが速い。

https://github.com/sassembla/SocketRoundabout-WS-NSDistNotif/blob/master/README.md



使用例

SocketRoundaboutでWebSocketサーバを立ち上げた状態で、

nginxから接続通してWebSocketサーバを外部に立ち上げて、インプットを別のところに転送できる。


WebSocketサーバ用意して、簡単になんか動かしたい、みたいなときに使っている。

wrote 2013/05/30 10:15:17

RubyMotionKaigi 2013


概要

RubyMotion Kaigi 2013

http://connpass.com/event/2095/


に参加してきた。肋骨折られるのヤダですし。

蛇足、Why RubyMotion: for me

強固な言語で作られた基盤の上に、柔軟性の高い言語を置く、っていうアプローチがいいなーって思っているなど。

Javaの型システムの上にJS走らせる某AltJSとか、

C++の横でプラグイン基盤としてPython走らせられるSublimeTextとか、


ガッチリ基礎があってその上で表現力豊かだったり楽に書ける言語で作るの良いよね~。



RubyMotionKaigiの話 基調講演トピック的な

by Laurentさん


Static analysys

静的解析、LLVMみたいなのをやるつもり、と。

LLVMが出来るところまで行けると、もうRuby,,,だっけ? ってくらい判りやすくなるんだろうな。



2.0対応

refinementsとかRuby2.0の機能もサポートするよ



RubyMotion 2.0系

by 「契約してMacRubyのコミッタになってよ!」でMacRubyにjoinしたwatsonさん。



比較、値渡しなどの親和性

RubyMotionはObj-C runtimeを利用してRubyを実装しているので、Obj-CとRuby間の値の関係がストレートに出来ている



MacRubyとの「差」

JIT(MacRuby)か、preCompile(RubyMotion)

MacRubyで書いたアプリをRubyMotionで書き直すと2倍くらい速くなる



OS X対応

わーいゾーンですよ。ちょっとした用をはたすにはアプリ作ると良いのですよ!


高速化

gemとかのキャッシュ持ったよ!

rake時に全消しされてたのから、キャッシュ化することでその分の時間をryだよ!


weak reference


Q,sugar cubeについて

is 何? 

便利ライブラリ集。ObCで書くと長いコードがRubyのシンタックスシュガーで解決できる。


why not include?

RubyMotuonはthinなものにしてるので、そのへんの便利な物は

組み込まないよ!



開発者の視点から 

by Naoya itoさん


最近の事例

37SignalsがiOSApp作ったよね

→実際使ってる。助かってる。

よくある質問

Obj-Cわからなくても使えますか? YES


iOSの知識が無くても使えますか? NO!

CocoaTouchのAPIを呼ぶのでな!


Ruby脳でiOS App作れると思った?→残念 さやかちゃんでした



tapもKVOも使える

ブリッジ系とは違うのだよ、的な。

Obj-Cの上でRubyが動いているので。


なるほどなー確かに筋がいい。



ARC風

メモリ管理は独自、not ARC、 not Ruby GC

中身はリファレンスカウンタ方式



Tips:ライフタイムが長そうなオブジェクトはインスタンス変数に入れる=強参照になる

オブジェクトのライフ周りにテを突っ込んでるの、かなり大変そうだけど、

Tipsがあることで「もしかしてこれが原因かも→試す→あってた、これだ」みたいな原因チェック我で来やすくなると思うので、

イタダキ。



RubyMotionのここが素晴らしい!

Vi■、Emacs or TextMate とかで使えるんだよ!(抄訳)



RubyMoとgems

sugarCubeべんり


NanoStoreInMotion

iOS向けのkvsのコントロールができる。ActiveRecord風インターフェース!

依存関係もあり


→rubymotion-wrappers.com に行け

Tips

・ビルドシステムまわりはOSSでRubyなのでハックしやすい。のぞくと良いよ


・Dashを使ってドキュメント見ると良いよ


・テストもいろんなツールがあるよ!

クソムシに気を取られてしまってあやふや



iOS使いがRubyMotionを使ってみたぜ!的なお話

by @mfks17 さん


RubyMine5からRubyMotion supportが始まったよ!

breakポイントにも対応



テストは書いた方が良い

三日前の自分は他人



もくもく会がすぐ埋まってしまうので勉強会を作る!

すげー




質疑応答

アクティブユーザーってどのくらいいるの?

→Laurentさん:正確にはしらぬ。

ユーザー数としては、数千人。今年中に1万人は超えると思う、とのこと。


アプリ数は?

→Laurentさん:しらぬ。 報告されないとわからぬし。 週一本は出てるんじゃないだろうか。



LT

RubyMotion in IRC

by @ninjinkunさん


テキストベースに向いてると思ったので、IRCアプリをRubyMotionで作ってみた

このアプリでの、「あの辺から持ってきたら動いた」話は、なんか今後もちょくちょく思い出す気がする。

扱う対象が同じで、実現するための手法も特定の形があるものなら、似通ったのそのまま持ってこれるよなーとか。

最近WebSocketで同じ感覚にあっている。



wrote 2013/05/29 18:45:43

JavaEEなアドバイスを完全に無視してWebSocketサーバ自作! ゆとり 22nd


概要

ゆとベントカレンダー (http://atnd.org/events/39189) 22日目です。

21日目は @kiyokura さんの ゆとりJavaScriptコーディング でした。


誤ってこのアドベントカレンダーを書くためのゆとりをぶっつぶしてしまったため、

今(2013/05/23 9:35:20)から書きます


ふぇぇ



起:よし、WebSocketServerだ

製作中のアプリケーションで、挙動チェックのために急遽WebSocketServerを立てることになりました。

Jettyでいいよね。サクッとね。うん。


承:某がんばれのひとにGlassFishを勧められる

スクリーンショット 2013-05-23 13.00.50.png


数秒後


スクリーンショット 2013-05-23 13.00.37.png


、、、これは使わざるを得ない! きっと。たぶん。



あの日あの時の、ゆとりある第三者の視点

スクリーンショット 2013-05-23 9.56.42.png



転:そして物語が

その夜、様子をみていた同僚から一つのリンクが届きます。

「前、Objective-Cサーバつくりましたよね。いいのみつけたのよ、WebSocket部分だけ、これベースで書き直したら速いんじゃ無いすか?」

これ:MBWebSocketServer https://github.com/mxcl/MBWebSocketServer


確かに、、会社のサーバ入れば、Obj-Cで2年以上前に組まれたサーバはある。っていうかXcodeから起動できる。

アクセスに対してブレークポイント貼りながら見れるからラクだ。



結:唐突に終わる

_人人人人人人人人人人人人人人人人人人人人人人人人人人人人人人人人人_
> アクセスに対してブレークポイント貼りながら見れるからラクだ!! <
Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y

実際に積んだところ、10分しないうちに動かせた。10分使ってしまった。アホである。

エコーサーバでよかったので、デフォルトで含まれてるJettyでもGlassFishでもよかったはずである。


ということで、


われわれは!!

起動直前まで行っていたGlassFishを!!

結局使いませんでしたァァァァア!!


すいません。

使ってみた記事必ず書きます。



23日は @zer0_u さんです


wrote 2013/05/22 9:28:18

Macアプリ、Obj-CでのNSDictionary略記法のダークなタイミング


概要

NSDictionaryの略記法使うと、理由不明のエラーが出るケース。

ずーっと自分のライブラリ疑ってたんだけど、違った。

下記ケースで、NSDictionaryの生成略記法 @{} での辞書生成が悪さをする。

ちなみにMac版アプリだけで発生を確認している。

iOS用だと、実機/シミュレータともに発生していない。



環境

Xcode 4.6.2

Mac OS 10.8.3

ARC:あり

Mac用アプリ



症状

IMPを指定してのメソッド実行で、そのメソッド内で

NSDictionary * dict = @{@"key":@"value"};


とすると、生成時は死なないが、メソッドを抜ける瞬間に


EXEC_BAD_ACCESS(code=12,address=0x0)


が発生する。

発生確率は10/100回、10%くらい。Jenkins見てる限りはそんな感じ。

環境差とかはわからん。


サンプルコード

#import "AppDelegate.h"


@implementation AppDelegate {

    SEL m_receiver;

}


- (void)applicationDidFinishLaunching:(NSNotification *)aNotification

{

    m_receiver = @selector(receiver:);

    

    // Insert code here to initialize your application

    IMP func = [self methodForSelector:m_receiver];

    (* func)(self, m_receiver, aNotification);

}


- (void) receiver:(NSNotification * )notif {

    NSLog(@"hereComes %@", notif);

    NSDictionary * dict = @{@"key":@"val"};//←

}


@end


←のあるラインで、この行を通過後、

(* func)(self, m_receiver, aNotification);

この行を抜けるタイミングでエラーになる。



サンプルプロジェクト

githubに上げといた。

https://github.com/sassembla/DummyProject


100回Jenkinsさんでまわして発生するか試してみた条件など

・ARCをオフにすると発生しない

・略記法@{}ではなく、通常記法だと発生しない


・辞書の内容を空にすると発生しない

NSDictionary * dict = @{}; だと、発生しなかった。


・switch文に入れ、通過しないcaseの中にあっても発生した

ぶっちゃけ原因追及に時間がかかった理由はこれで、

switch文、しかもその時点では内容が存在するcaseを通過しない、という条件にも関わらず、発生している。


switch文を加えた、下記コードでも問題が発生する。

- (void) receiver:(NSNotification * )notif {

    NSLog(@"hereComes %@", notif);

    

    int a = 0;

    

    switch (a) {

        case 0:{

            break;

        }

        case -1:{

            NSDictionary * dict = @{@"key":@"val"};//←

            break;

        }

            

        default:

            break;

    }

}


aが0なのは自明だし、switch文で0に飛び込むので、まーなんも起こらねーだろと思ったら、発生した。

略記法の内容生成自体はswitch文生成と一緒に行われてるんだろうな。

実際にallocするかどうかは別として。



発生確率を上げる方法

特に思いついていないが、複数、辞書の初期化コードを書くとかしても、発生率に変化は無かった、、とおもう。たぶん。


誰かのハマりの助けになれたらと思うが。

なんかあったらgithubのIssueでもください。

スクリーンショット 2013-05-14 17.01.32.png

wrote 2013/05/14 16:16:51

MacでのJenkinsの権限設定


概要

手元のスクリプトとかを動作させたい場合、権限が大事になってくる。

/Library/LaunchDaemons/org.jenkins-ci.plist を編集する。


参考

http://319ring.net/blog/archives/1960



Groupをstaffに

userをJenkinsからユーザー名に。

sudo chown -R ユーザー名:staff /Users/Shared/Jenkins/Home



終了

sudo launchctl unload /Library/LaunchDaemons/org.jenkins-ci.plist


起動

sudo launchctl load /Library/LaunchDaemons/org.jenkins-ci.plist


wrote 2013/05/13 16:23:21

Macアプリと連携する独自拡張子の作り方


概要

独自拡張子が欲しかったのです。どうせ内容はテキストなんですけど。

ダブルクリックしたら特定のアプリが起動する的な。

はい。



.byaa拡張子のファイルをダブルクリックすると開くアプリケーションを作る

必要な設定は2つ。


・AppDelegateに、

- (BOOL)application:(NSApplication * )theApplication openFile:(NSString * )filename

メソッドを書く


・Xcode > ProjectNavigator > TARGETS > なんかtarget > Info > の下の方の、Document Types 項目の+を押す

スクリーンショット 2013-05-10 21.59.16.png

なんか設定画面が出来るので、Extensionsに形式を指定する。どっと要らない。


これだけ。



これだけで

.byaaファイルをダブルクリックすると、アプリが起動するようになる。


ダブルクリックで.byaaファイルを開くと、- (BOOL)application:(NSApplication * )theApplication openFile:(NSString * )filename メソッドに通知が行き、

filenameにダブルクリックしたファイルパスが入るので、そこで読むとかすれば良いと思う。


ちなみに通知はアプリケーションのLaunchより速く発生する。


- (BOOL)application:(NSApplication * )theApplication openFile:(NSString * )filename

- (void)applicationDidFinishLaunching:(NSNotification * )aNotification

返り値は、ドキュメントいわく

YES if the file was successfully opened or NO if it was not.

オープンが旨くいったらYes返すと良いよ、他はNoでいいんじゃね

YESでもNOでもアプリは起動する。し、起動しててももちろん発生する。


何に使っているかというと、NSAppが発生させるNotificationのトリガーに使っている。

ただ、表立って効果がない。区別は出来る。 Notificationを無差別に拾ってみると、なんか違いがあると思う。

https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ApplicationKit/Classes/NSApplication_Class/Reference/Reference.html



スクリーンショット 2013-05-10 21.56.15.png

いやーーーらっくちんだなァ~。


wrote 2013/05/10 21:52:40

SublimeTextに選択式入力窓が付いたよ的な話


概要

ST3 build 3033 が出ました。

http://www.sublimetext.com/3


いやー全然気付かなかったんだけど、APIドキュメントとか更新されてたんですね。

http://www.sublimetext.com/docs/3/index.html



相変わらず

view.sel.contains(region)がboolではなくNoneを返してくるんだけど、

そのへんはまあそのうち変わるのかな。

→バグだったらしくfixされてた。

http://www.sublimetext.com/forum/viewtopic.php?f=6&t=12888



選択窓

EclipseとかIDEにあって、SublimeTextにずっとなかったもの、それが「選択窓」。

が、ついにST3で付いたようです。


まだ途中感溢れるんだけど、

こんな見た目

sel.png


こんなコード

# 実行時に呼ばれる関数、resultには、成功時にindex、キャンセル時に-1が返る。

def test(self, result):

  print("done", result)


# これで、2択が出る

view.show_popup_menu(["abcdef","abcdefa"], self.test);


んで、あとは関数内で、文字列を呼び出してどうこうすればいい、と。


上下キー、カーソル、STの入力追随の3つの方法で選択できます。



補完候補を、STの推論の外から持ってきておいて選ぶ、が出来ますねー。待ってました。


行動のトリガーにも出来るので、たとえば

テストコードの行頭を選んで、実行 とか選ばせるのを作ってみようと思います。


ラク! 速い! 軽い!!



牛丼みたい。



SublimeSocket for ST3

以前四国旅行中に手を入れてたんだけど、残すはview.selの問題のみです。

はー待ち遠しい。


wrote 2013/05/10 18:44:26

IT技術者が教える本当に失敗しないBBQ ~肉とカレーの祭典編~


概要

ゆとりアドベントカレンダー5日目です

http://atnd.org/events/39189


本日行われたBBQ[ぬる舗Presents 肉とカレーの祭典2013]にて、何個かの「本当に失敗しない」テクニックが披露されました。

本アドベントカレンダーにふさわしく、また、みなさんにも是非知っておいてほしい内容だったので、

ここに大公開しておきます。


Side-A:本当に失敗しない、10人分のお米を20分以内に炊飯するテクニック


0.準備

まずコメを用意します。BBQ会場で炊きます。

rice_image.jpg

違和感を感じましたか? 気のせいです。




1.お湯を沸かす

BBQユニットに水をたっぷりといれたナベを載せ、

おもむろに炭火でお湯を沸かします。

a.png


お湯が湧いたら、上記のごはんをこう、、ボイルする感じで、ダイブさせるのです。そういう予定。

あとは待つだk




20分もすれば、@itog さんがおもむろに手をつっこんで、「あーー、、風呂で入るにはちょっときついくらい熱い」

と的確な意見をくれます。




2.お湯を捨てる

気が済んだらお湯を捨てます。



3.コンビニを探し、米を持って移動

海浜公園からちょっと出て、コンビニを探します。

今回は近所にありました。 迅速に、米をもって移動します。

スクリーンショット 2013-05-05 23.01.27.png



4.1500wを使用する

IMG_1303.png

その場で購入したお米、

持ち込んだお米を、2つずつ入れて、1分20秒チンします。


コンビニとの交渉にいちばん神経をつかいましょう。

おかしなこと言ってるのはこっちです。



.完成!!

さっさと現場へ戻り、暖めておいたカレーをかけて、焼肉を添えて、いただきます!!

d778b168b53811e2a5e422000aaa08f8_7.jpg



SIDE-B:本当に失敗しない鳥まるごと一羽ホイル焼き

0.炭で囲んでみよう

したごしらえした鳥(一羽まるごと)を、アルミホイルでつつみ、炭の間にぶちこみます。

IMG_1309.png



1.展開しよう!

おもむろに開きます。

BJg6FUdCMAI0fS2.jpg-large.jpeg



3.やっぱり小分けにして焼こう!!

v.png


めっちゃおいしかった。



おまけ

あきすてさま's GF劇場

IMG_1310.png

あきすてさまの生GFが聞けるかと思ったんだけど聞けなかったので腹いせにupします


写真は、参加者のみんなからいろいろいただきました! 感謝!

IMG_1305.png


うまかったわ~~~



明日のゆとりアドベントカレンダーは、、えっと、、、

@sue445 さんです!





wrote 2013/05/05 18:59:55

nnotifd NSDistNotifで制御するObj-C製CL実行デーモンみたいなの


概要

コマンドラインから起動して、Mac内を駆け巡るNSDistributedNotificationを受信、

特定の形式だった場合、コマンドラインを実行するプログラムを作った。

Macアプリではなく、Macコマンドラインアプリ。


nnotifdというコマンド名にした。

https://github.com/sassembla/nnotifd


スクリーンショット 2013-05-01 22.24.17.png


SocketRoundabout

(WebSocketP、BT、HTTP、NSDistNotif、他、通信プロトコルを相互接続するツール)

と組み合わせて使う。


単体でも使い道があるとは思うが、わざわざそのために脳みそ使って考える必要も無いだろう。



動機

どんなニーズがこれを作らせたか、というと、

・Mac環境、サーバサイドで動く、コマンドライン実行クライアントが欲しかった

→SocketRoundaboutがその機能を持ちたくないので、コマンドラインを外部で動かすもの、という位置づけのプロダクトが必要だった。


・コマンドライン実行自体を、NSDistributedNotificationをトリガーとして行いたかった

完全にSocketRoundaboutが話せるプロトコルだった、という都合。

→そういえば大昔につくったObj-Cサーバあったよね!

ということで、改造していろんな機能オミットしまくって、こうなった。


ちなみにデーモンって言ってるけどまだぜんぜんデーモンじゃない。


形式

会社でつかってる独自形式(文字列+JSON)をベースに、適当にコピーした形式を使っている。

SublimeSocketとほぼ同系統だけど、こっちのほうが機能が圧倒的に少ない。必要ないしな。


全体

nn:[JSONARRAY]


ヘッダ

nn:

パラメータ

[JSONARRAY]


という形の文字列を送り込むと、コマンドラインとパラメータとパイプを解釈して、コマンドラインとして実行される。



例's

始動

nnotifd -c start -i IDENTITY


で、アイデンティティ = nnotifdが受信するチャンネル、という風に設定して起動できる。

別に起動と同時にスタートしないでもいいんだけど、-iでの「受信するアイデンティティの決定」だけは必須。


nnotifdとのコミュニケーションには、NSDistributedNotificationを生成すればOKで、

これはキーとかが合ってればプロセス間を跨ぎ放題、なんでも送ってOKというゆっるーい感じになっている。


実行順は発行順と同じにならない(順保証がされない)ので、使いたい部分だけ注意して作った。

実際には準保証をするための仕掛けもNSなんちゃらには用意されているが、テストしづらかったので、これから順保証モードとして着手する。


なんかNSDistNotif越しの実行がしたい場合、

nnotifdを起動したあと、


付属のnnotif(入力した文字列をNSDistNotifにして発行するツール)で送付するか、どっかObj-Cで書いて送り込む。

nnotif -t IDENTITY -k NN_DEFAULT_ROUTE -i nn@ -kill

これでkillできる。

-iはnnotifのオプションで、input。 nn@以降の文字をnnotifdに対するコマンドとしてIDENTITYに対して送り込む。


Obj-Cで書く場合、

[[NSDistributedNotificationCenter defaultCenter] postNotificationName:IDENTITY object:nil userInfo:dict deliverImmediately:YES];


で良いと思う。dictの中身はパラメータになる。

コレに関しては、nnotifが | を受けられるため、コマンドラインから使えるほうが万倍いろんなことができる。



nnotifdで特定のコマンドラインを実行したい場合、

nnotif -t IDENTITY -k NN_DEFAULT_ROUTE -i nn@ -e nn:["/bin/pwd"]


とかで、pwdが実行できる。

nn@ までが入力のためのヘッダ、-eから先がnntoifdで実行されるコマンドの独自形式JSONArray。


pwdがフルパスになってるのは、これの内部実装がNSTaskを使用しているので、コマンドのありかのパスを総て書かないと動かないため。


nnotifd内で使用したいコマンドに対してパイプを使う事もできて、

nnotif -t IDENTITY -k NN_DEFAULT_ROUTE -i nn@ -e nn:["/bin/cat","/SOMEWHERE/SOMETHING.txt","|","/usr/bin/grep","-e","KEYWORD"]


とかで、

/SOMEWHERE/SOMETHING.txt に対してgrep KEYWORD を実行する、みたいなのができる。



おまけで、nnotif自体がパイプを扱えるので、

tail -f /SOMEWHERE/SOMETHING.log | nnotif -t IDENTITY -k NN_DEFAULT_ROUTE

とかで、tail結果をダイレクトに、連続した状態でどこかへと送り込める。

もちろんnnotifdのなかでnnotifを使用して別のNSDistNotifを発生させることもできる。


これで、例えばサーバからのメッセージを受けて特定のコマンドラインを実行したり、

実行した内容を同種の通信手段を使っているSocketのおばけみたいなプロダクトに送り込んだりできる。



具体的な用途

特定のコマンドラインを実行し、その結果を、nnotifなどを使い、NSDistNotifで送り出す。

NSDistNotification -> BT とか、

NSDistNotification -> WebSocket とか、そういう転送ができるツールがあるので、

そのツール自体のコントロールとか、プッシュの「起点」に使用する。


そうっとう異様なニーズに応える代物。


組み合わせで、WebSocketClientをサーバサイドでnodeとかより安定した挙動できるように動かそう、みたいな

ニーズに応えるために作った。

ぶっちゃけnodeの難解なコントロールに耐えられなかった人間が狂気で作った何かのためのパーツ。



wrote 2013/05/01 13:42:59

SublimeSocketmruby対応


概要

今はmrubyな人なますいさんと飯喰っててやってみるか的な感じになったのでやってみる事に。


SublimeText + SublimeSocket + mruby + Chromeで、

ST上で保存した.rbなコードをmrbに変換したり、構文エラーとか実行時エラーとかをST上に表示する。

スクリーンショット 2013-04-27 23.41.28.png

Mac用。いまのところ。



SublimeSocket mruby support

一応使えるようになったので、公開まで。Mac用しか試してない。

https://github.com/sassembla/SublimeSocket



自分が使っている環境が、下記

Mac OS10.8.3、

SublimeText2、

Google Chrome 26.0.1410.65 、 

mruby わからない. --versionでバージョン表示出ないので2013/04/27 00:00:00あたりにgithubにあったやつ。



TypeScript用のものと全く同じインストール方法なので、ぱっと見のインストール法とかは下記TSのものを見ると良いと思う。

SublimeSocket + TypeScript ~さよなら! node.js強依存~ 編

http://sassembla.github.io/Public/2013:04:03%202-27-52/2013:04:03%202-27-52.html



詳しいインストール解説

(順不同)

0.STにSublimeSocketをインストール

0.mrubyをインストール

0.Chromeに、SublimeSocketフォルダのtool/ChromeClients/MrubyClient をインストール

0.SublimeSocketフォルダのtool/ChromeClients/MrubyClient 内の、MrubyClientDelegate.js ←JSな事に注意

内の、mrubyバイナリの置き場を自分がインストールした場所に書き換える。(下記画像参照)

スクリーンショット 2013-04-27 21.57.18.png


1.mrubyで弄りたいソースコードをSTで開く

2.SublimeSocketをonに

3. 1と同じフォルダに適当にログ書き込み用ファイルを作る

4. 3をChromeに放り込み、そのタブでmrubyClientを起動


これで、1で開いたファイルを保存するたびにmrubyが走り、フォルダ中の.rbコードがすべて実行される。



2つの動作モード

mrbcコマンドを使ってフォルダ内の全.rbコードをmrbへと変換しようとするmrbcモードと、

フォルダ内の全.rbコードをmrubyで動かすmrubyモードがある。


モードの切り替えは、やっぱりtool/ChromeClients/MrubyClient 内の、MrubyClientDelegate.js を手で書き換える。

スクリーンショット 2013-04-27 21.58.32.png


デフォルトではmrubyが走るモードにしてある。




以下おまけ。




実は静的型付きコンパイル言語以外のものをSublimeScoketにつなげるの初めてだったことに気付いた

今回、mrbcのことを勘違いしてて、


.rbファイルの内容をちょっとは静的解析して.mrb吐いてるものだと思っていた


ので、下記のようなコードでエラーがでないのが不思議で不思議でならなかった。


j = q

mrubyで実行したらばまあ qがねーぞクソが! みたいに言われるんだけど、


てっきりこう、ほら、コンパイルとか聞くとさ。

そのへんのエラーが出る物だとさ、ほら、思い込んじゃってたわけさ。暗黙のコンパイル脳でさ。


あっじゃあ保存時にmrbcでコンパイルするだけでもなんかエラー検出とかいい感じなんじゃね? って思っちゃったんだよ。

でまあ、パァーっと書いちゃったんだ。


ごめん。ごめんなさい。生きててすいません。赦してルビーストな人たち、、、

ただ、構文エラー検出しても、サイズ0の.mrbファイル吐くのはなんなんだろう。。


とりあえず出来た

構文チェックは当たり前のように素晴らしいので、

j = 


とかだけ書いた物をmrbcしようとすると、

/s.rb:1:4: syntax error, unexpected $end

やった、、!! やっと怒ってくれたね、、!!!

というわけで、

保存→ mrbcで構文エラーのコード上表示

or

保存→ mrubyで実行時エラーのコード上表示


のどっちかを選ぶ事が出来るようにした。

動作時の参考までに、

実行時のエラーをSublimeTextのコード上に出してみた、の図。


これは、jなんて関数ねーんだけどって言われてる画面。

スクリーンショット 2013-04-27 17.10.49.png

実行時のエラーをST上に表示できる。



下のは、文字列にマイナスなんてメソッドねーよカスがって言われてる画面。スクリーンショット 2013-04-27 21.13.23.png


wrote 2013/04/27 0:25:29

このインスタンスの年齢がインクリメントされました


概要

もーーあと一年すると0x20歳になれるかと思うと感慨深いです。



今年齢フェーズにおける抱負

がんばりたくありません。


型とかは積極的に推論されていきたいですし、

;とかも書かなくていい過ごしやすい世の中になってきたと思いますので甘えます。


あとゴミ処理、これも自動化した環境で過ごしたいですね。


具体的には

”くろーjゃ”、

"Eーらん"、

"すかla"

推しで行きます。去年とぜんぜん変わらない。


あと"ユニtィ"で適当に遊んだりとか。



あっあとその、、えっと、、恥ずかしいんですけど、、

これ、、あらん限りの素直な欲望をさらけ出してみたんで、、、その、、

笑わないで見てください、、、


http://www.amazon.co.jp/registry/wishlist/2D3SR1UW6O6U2



wrote 2013/04/24 00:00:01

Macに nginx をインストール


概要

過去最高にタダのメモ。


homebrew経由でインストールする

highvision:~ sassembla$ brew install nginx --devel

でOK


あとは、下記を参考に起動とか設定とか。

http://learnaholic.me/2012/10/10/installing-nginx-in-mac-os-x-mountain-lion/



起動

sudo nginx

で、8080での起動がなされている。

停止

sudo nginx -s stop



設定変更

ポート番号の変更は、下記設定ファイルを弄る。

/usr/local/etc/nginx/nginx.conf



で、完了の図

スクリーンショット 2013-04-16 21.01.57.png

やったねたえちゃん!



WebSocketのフォワーディングをしてみる

設定は下記を参照

http://qiita.com/items/484aa9bfb7bc4206ffed


/usr/local/etc/nginx/nginx.conf


    server {

        listen       80;

        server_name  localhost;


        #charset koi8-r;


        #access_log  logs/host.access.log  main;


        location / {

            proxy_pass http://127.0.0.1:8823/;

            proxy_http_version 1.1;

            proxy_set_header Upgrade $http_upgrade;

            proxy_set_header Connection "upgrade";

        }


かんたんですね。

wrote 2013/04/16 20:31:22

宮川製麺所

香川県善通寺市中村町1-1-20スクリーンショット 2013-04-13 16.47.12.png

かなり遠い。



いなか道 根っ子

香川県スクリーンショット 2013-04-13 16.51.38.png仲多度郡多度津町大字青木565-2

駅から車で10分らしい



麺や 丸亀田村店

香川県丸亀市田村町613-1

スクリーンショット 2013-04-13 16.56.44.png

電車でゴウンゴウン行ってみるか。



麺処 綿谷

香川県丸亀市北平山町2丁目618

スクリーンショット 2013-04-13 17.02.40.png



上戸うどん

香川県観音寺市豊浜町箕浦974-1

スクリーンショット 2013-04-13 17.04.17.png

めっっちゃとおい。却下。


JR丸亀駅

この近辺を根城にすると捗りそう。

帰りに高松にくればいいのか。

wrote 2013/04/13 16:43:05

TypeScriptでChromeのExtension書いてハマったとこメモ


概要

ChromeExtensionをTypeScriptで書いてみてた。

TypeScript化しつつあるブツはこちら。

SublimeSocketでのTypeScriptコンパイル機構


ChromeExtensionsのJSをTypeScript化することのメリットは、今回の場合下記を目論みつつ。


・クラス!! クラス!! クラスがホシイ! デフォで!!

・extendsを使った振る舞いの置き換えが簡単に素敵!

・コンパイル時型チェックあるしミスに気付くチャンス増えてラク


などなど喧嘩売ってるように見えなくもない感じ。



成果物

各言語対応に簡単に対応したいため、extendsでmethod実装さえすれば動くようにした。

https://github.com/sassembla/SublimeSocket/tree/dev/tool/chromeClients/TypeScriptClient



ハマったとこ列挙してく


1.chrome.*とのお付き合い

TypeScriptさんはchromeなにやらのことを知らないので、

declareで何が来ても吃驚せずコンパイルしてもらう事にします。


declare var chrome;


で、

chrome.browserAction.onClicked.addListener(function(tab) {};

chrome.windows.getAll (function(windows) {});

chrome.browserAction.setIcon({path:"images/icon-inactive.png"});


とかがTS内で使えるようになるので、他の、かっちり構造的にすべきところに注力する事が出来る。

他にはWIndow系とかがあるけどこの辺はもう普通のTSの使い方と変わらんす。


d.tsを探せばどっかあるだろとか思ったんですが、なかなか変化しそう+使用するメソッドも関数渡しがメインだったので、今回は使ってないです。

ちなみにd.tsをつくった方、こちら。


borisyankov / DefinitelyTyped

https://github.com/borisyankov/DefinitelyTyped

の、

https://github.com/borisyankov/DefinitelyTyped/pull/93/files

あたり。


このひとすげーな。



2.extendsとロード順

ChromeのExtension、使用するjsをmanifest.jsonに定義するところについて。


~中略

    "background": {

        "scripts": [

            "Something.js"

        ]

    },

~中略~


とか書くわけだけど、

TypeScriptで、

クラスParentとクラスChild(ChildはParentをextendsする、みたいなとき、


class Child extends Parent {

}


class Parent {

}


scriptsのロード順(!)を気にする必要がある。

manifest.jsonファイル内のscripts配列の要素のアタマから順に読んでるんだと思うので、


    "background": {

        "scripts": [

            "Parent.js", "Child.js"

        ]

    },


で、実際のクライアント上でもちゃんと動く。


読み込む順にv8に喰わせてるかなんかだと思うので、

順番をChild.js -> Parent.js とかにすると、Parentなんか知らねーよ、とエラーで怒られる。


もちろんTS自体のコンパイル正否とは無関係に。

複雑になってくると詰む。面倒くさくて。

→extends関係を考慮して云々するより、concatnateしてしまえばいいじゃない!


と思ったんだけど、これはこれで下記3のカドに小指がぶつかる。



3.--outオプションによる死亡

コンパイル物を1ファイルに纏めるべく、tscに--outオプションを付けるなどすると、

Extension読み込み時に

Uncaught TypeError: Cannot read property 'prototype' of undefined

が、出る。


原因箇所はこんな感じ。

スクリーンショット 2013-04-10 23.57.02.png


条件としては、

・extendsを使用している

・--outで固める

の組み合わせ。


一発で読んじゃえばいいじゃない→中身の順番でアバー というパターンにハマった。

extends自体の定義で問題が起きてる。


ちゃんと読むとかすれば解決できると思うけど、

manifest.json のscrptsの記述順番による解決の方がなんぼかラクだったので、日和って回避した。


ChromeExtensionsでのコードが大規模になった時(って来るの? 来ないでしょ)不味い。

例では、class WS が class WSControlBasement をextendsしてるので、そのための定義順だと思うが、

extendsされるクラスが先に定義されてないから駄目なんじゃないかなあと思うなど。


あっ名前については見逃してください、、あくまで仮です。


他に、staticとかもヤバい予感がする。

順番指定して--out、とかもイヤな話だしなあ、、



オプションについては下記が自分の覚えてるすべてなので、

http://sassembla.github.io/Public/2012:10:20%2022-46-41/2012:10:20%2022-46-41.html


現行のオプションを試すともっといろいろ面白い事が出来るかもしれない。


コレ書いてる時の最新、0.8.3では、tsc.jsの24502行目から先につらつら書いてある。

無くなってるオプションもけっこうあるような。



4.chrome.*で発生したエラーのデバッガでの表示位置が微妙にずれる

chrome.*系のメソッドは、TSからはdeclareしてるだけだと、特にそれらのメソッドについての型チェックが行われるわけではない。

chrome.*をd.tsで定義してればまともに出る、、かなあ、、 sourcemapの出番だよなー。


いちおうどうズレるかの例として、

chome.browderAction.onClicked に渡すパラメータを間違えると、下記エラーが出て、エラー行の表示が可能なのだが、

スクリーンショット 2013-04-11 17.36.24.png

正し、エラー行の表示は原因行から若干”上”の行になる。

下の画像では、console.logで出た事になってる。


このTips、ぶっちゃけts関係ない。

スクリーンショット 2013-04-11 17.36.34.png

以上!


wrote 2013/04/10 21:25:10

SublimeSocket API Reference 1.1.3


Overview

SublimeTextのAPIを、WebSocket経由で実行するためのサーバです。

SublimeTextのプラグインとして実装されています。


WebSocket(RFC6455)によって、Local, Remoteの環境と組み合わせて動作します。


文章中では、SublimeTextのことをST、SublimeSocketのことをSSと略機することがあります。



用途

・SublimeSocketAPIを組み合わせてReactorをプログラミングし、ST上にログ情報を表示

・ST上での特定のアクションに応じてコンパイル処理を走らせる

・Remote環境のコンパイラとLocal環境のSTの連携

・端末上のWebSocketクライアントとSTの連携



想定している連携例

スクリーンショット 2013-04-05 13.27.48.png

サーバ側から、Log、StackTrace、SublimeSocketAPIなどの文字列データをSublimeSocketへと送付

SublimeSocketがデータ受信、API受付

SublimeTextに表示、編集アシスト動作


SublimeTextからキーイベント発行

SublimeSocket イベント着火

SublimeSocketからサーバ上のコンパイラにコンパイルオーダー

サーバ側でコンパイル


ずっとSublimeTextのターン!!



API記法について



SSJSON (SublimeSocketJSON)

JSONに特定の文字列をつけて、APIの実行キーにしています。

下記の文字で構成された文字列を受け取る事で、APIを実行します。


Prefix

API_PREFIX = "sublimesocket"

API_PREFIX_SUB = "ss"

特にSublimeServer向けの情報である事を示すPrefixです。

ぱっと見で明示するために付いています。

フルに書くのがめんどくさい場合、ssで済ます事が出来ます。



HeaderDelimiter

API_DEFINE_DELIM = "@"

ここから先がAPIのKeys and Values、という事を示すデリミタです。



Concat

API_CONCAT_DELIM = "->"

API同士を接続するデリミタです。

下記のように使用します。

ss@API->API->API

-> で連結したAPIは、記述順を守って実行されます。

Parameters

ss@Command1:JSON


ss@Command1:JSON->Command2:JSON->Command3:JSON,,,


JSON部分の内容は、各APIごとに必須パラメータ名、型が決められています。

また、パラメータ無しのAPIは、JSON部分無しで実行する事が出来ます。


ss@Command1



Comment

API_COMMENT_DELIM = "/"

@とAPI名の間に記述する事が出来ます。/で閉じます。


ss@コメント/API->...



値渡し

Returnが定義されているAPIの場合、

(SourceKey|TargetKey)をAPI名の前に書く事で、直前のAPIの結果値を渡すことが出来ます。

1.0では特定APIにしか対応していませんが、1.1では全APIで対応する予定です。

ss@commandA:{"key1":"value"}->(key1|key2)commandB:{"key2":"will be replaced."}

commandA の key1 に入った値を、commandB の key2 へと入力して実行します。



Sample API

下記は、STのログに "Hello World" を出すAPIのサンプルです。

ss@ハローワールドです/showAtLog:{"message":"Hello World"}


色々なAPIを、SublimeSocket Test Console で試す事が出来ます。

CommandPalette -> "SublimeSocket: on > open preference" で、SublimeTextからSafariなどブラウザが起動します。

スクリーンショット 2013-06-10 18.55.42.png

input に対してss@showAtLog:{"message":"Hello World"}を入力した状態でInputボタンを押すと、SublimeText内のコンソールに ss:Hello World と表示されているはずです。


c.png





API Reference



versionVerify

Client側から想定しているST、SSのVersionを入力し、SSのVersion、SSのAPIVersionとの整合性チェックを行います。

SSには、SS自体のversion と、SSのAPIのversionの2つのレイヤーがあります。


SSのversion = SublimeText 2 or 3 のどちらに対応しているか

SSAPIのversion = SublimeSocket API version


socketVersion[string]

Client側が想定しているSublimeSocketのversionの文字列です。"major.minor.changeLevel"

Client側の指定したversionと一致しない場合、そのクライアントとのコネクションは切断されます。


apiVersion[bool]

Client側が想定しているSSAPIのversionの文字列です。 "major.minor.changeLevel"


以下のケースが発生します。

major version について

client < server で切断、clientのupdateを促す

client = server でminorのチェックに入る

client > server で切断、SSのupdateを促す


minor version について

client < server で、OK、かつclientのupdateを促す(可能であれば)

client = server で、OK。

client > server で切断、SSのupdateを促す


e.g.

ss@versionVerify:

{

    "socketVersion": "0.0.1",

    "apiVersion": "0.0.1"

}



runSetting

テキストファイルとして保存されているAPIを読み込み、実行します。


path[string]

読み込むファイルのパスです。

SUBLIMESOCKET_PATH:と付ける事で、SublimeSocketフォルダ内を参照するようにショートカットができます。


e.g. /Users/someone/Desktop//UnityFilter.txt ファイルを読み込み、APIとして実行

ss@runSetting:

{

    "path": "/Users/someone/Desktop/UnityFilter.txt"

}



inputIdentity

SublimeSocket WebSocketのコネクションに名前をつける事が出来ます。


id[string]

コネクションに付ける名前です。

SSを中継して他Clientにメッセージを送る際などの宛名に使用します。


e.g. 送付元のClientのidをmyClientにする。

ss@inputIdentity:{"id":"myClient"}



tearDown

SSのWebSocket service を終了します。


e.g. SSのサーバを落とす。

ss@ tearDown

(バグがあり、socket自体はそのまま生存、address already use が出てしまう 2013/04/05 10:35:52)



setReactor

SublimeSocketに対して、特定のEventが発生した場合に動く、Reactorをセットします。

eventとtargetの組み合わせによって、特定のEventに対して複数の動作をセットすることが可能です。


event[string]

監視する対象のEvent名 "on_modified", "on_selection_modified", "on_pre_save", "on_post_save" など、

SublimeTextが発行するものと、

"event_"で始まる語句で、独自のイベントを定義できます。


target[string]

Reactorの識別に使用します。

異なるtargetを設定する事で、同じEventに対して複数のReactorをセットする事が出来ます。


selectors[JSONArray[JSONObject[string:any]]]

Event発生時に動作するAPIを記述できます。

記述はJSONの配列形式で、APIのCommand部分を文字列キーにしたJSonObjectが使えます。


interval[int]

実行間隔の数値です。

0であればセット直後に一度だけ対象Eventの発生をチェックします。

0以外の正の数であれば、ミリ秒ごとに対象Eventの発生をチェックします。


replacefromto[JSONObject[string:string]]

Reactor発生時、Eventの持つパラメータを、selectorで指定したAPIに適応させる事が出来ます。

{key:value}に対して、 Eventの持つkey名のパラメータの値を、selector内のvalue名のパラメータの値にします。


e.g. 選択範囲が更新されたら、STのログにHello Worldと表示する。1秒ごとに実行される

ss@setReactor:

{

    "target": "sublimesocketpreference",

    "event": "on_selection_modified",

    "selectors": [

        {

            "showAtLog": {

                "message": "Hello World"

            }

        }

    ],

    "replacefromto": {

        "view": "view"

    },

    "interval": 1000

}



setFoundationReactor

ST上で発生する特殊なEventに対してReactorをセットします。

Eventについては下記EventReference参照


event[string]

対象Event名です。”ss_f_noViewFound” などが該当します。

あるビュー(ファイル)に対する操作が発生したとき、そのビューが現在開かれていない際に発行されます。


条件があり、

・defineFilterが定義済み

・そのfilterにヒットするfilteriingが流入し

・対象ビューが探知できなかった

場合に発生します。


selectors

replacefromto

同 setReactor


e.g. Reactorセット後、フィルタ定義をし、そのフィルタにヒットするも該当するビューが開かれていない場合、STログにHello Worldを出力する。

ss@setFoundationReactor:

{

    "event": "ss_f_noViewFound",

    "selectors": [

        {

            "showAtLog": {

                "message": "Hello World"

            }

        }

    ]

}

->defineFilter:

{

    "name": "04/04/13 23:30:08",

    "patterns": [

        {

            "something": {

                "selectors": [

                    {

                        "showAtLog": {

                            "message": "Hello World"

                        }

                    }

                ]

            }

        }

    ]

}

->filtering:

{

    "name": "04/04/13 23:30:08",

    "source": "something"

}



kvs

SS内のKey value storeを扱うAPIです。

内部的にはPythonの辞書で実装されています。 この機能の実装は、そのまま別のKVSへとすげ替える事を念頭に隔離して実装されています。


showAll[string]

全パラメータを文字列にSerializeしてClientへと返します。

valueの意味はありません。


showValue[string]

valueにしたパラメータをkeyに持つ値を返します。

辞書や配列の場合、Serializeしたものを返します。


removeValue[string]

valueにしたパラメータをkvsから削除します。


clear[string]

kvsを空にします。

valueの意味はありません。


e.g. kvsを空にする。

ss@kvs:

{

    "clear": "true"

}



defineFilter

SSへとデータが流し込まれた際に反応するフィルタを定義します。

定義されたフィルタはkvsへと保存され、特定のデータに対して反応します。


name[string]

フィルタをidentifyするための文字列です。

filtering APIと合わせて使用します。


patterns[JSONArray[JSONObject[string:any]]]

正規表現をkeyにしたJSONObjectの配列です。

keyにマッチするデータが流入した場合、value内のselectorsがAPIとして発生します。


複数の正規表現を書いた場合、配列順に実行されます。

複数のフィルタにマッチすることを許します。


e.g. 2013/04/04 23:30:08 という名前で、somethingで始まるデータが流入した場合、STログにHello World を出力する。

ss@defineFilter:

{

    "name": "04/04/13 23:30:08",

    "patterns": [

        {

            "^something": {

                "selectors": [

                    {

                        "showAtLog": {

                            "message": "Hello World"

                        }

                    }

                ]

            }

        }

    ]

}



filtering

SSへとデータを流し込むAPIです。

任意の文字列データをClientからSSへと流し込みます。


name[string]

ターゲットとなるフィルタをidentifyする文字列です。

事前にdefineFilterでセットされている必要があります。


source[string]

文字列データです。

APIの都合上、JSONで扱えない文字と、-> (-と>の連続) が入っている文字列を扱う事が出来ません。

これらは事前にパースするとかでなんとかしてください。


debug[bool]

デバッグ用パラメータです。

セットされている場合はvalueに応じてデバッグ表示がSTのログに出力されます。


e.g. 2013/04/04 23:30:08 という名前が付けられたフィルタに対して、something という文字列を出力する。

ss@filtering:

{

    "name": "04/04/13 23:30:08",

    "source": "something"

}



containsRegions

通常、setReactorに内包して使用します。

特定のview(STで開かれているファイル)について、Reactorが指定したEventが発生したタイミングで、

エディタの選択範囲にSTのRegionが存在する場合、emitキーワードで指定したEventを発行します。

発行できるEventは、"event_" 句で始まっていればOKで、自由に定義できます。


Eventについては下記EventReference参照


view[string]

viewのファイルのパスです。


target[string]

この文字列をtargetとして持つsetReactorへと、Eventを発行します。


emit[string]

Event名の文字列です。

event_で開始していればOKです。 event_errorEmitted などが指定できます。


debug[bool]

デバッグ用パラメータです。

セットされている場合はvalueに応じてデバッグ表示がSTのログに出力されます。

e.g.  ファイル /Users/USERNAME/Library/Application Support/Sublime Text 2/Packages/SublimeSocket/SublimeSocketAPISettings.py に対して、

10行目にRegionが表示されます。

スクリーンショット 2013-04-05 0.19.31.png

そのRegionをカーソルが選択範囲に含んだ際、

sublimesocketpreference というtargetをもち、event_errorEmitted Eventに反応するReactorに対して、Eventを発行します。

viewパラメータは something Reactorのreplacefromtoによって、on_selection_modifiedが発生したviewへと置き換えられます。

Event発行後、event_errorEmitted に反応するReactorが発生し、Hello WorldがSTのログに出力され、 appendRegionの内容が実行されます。

b.png

ss@setReactor:

{

    "target": "sublimesocketpreference",

    "event": "on_selection_modified",

    "selectors": [

        {

            "containsRegions": {

                "view": "will be replace to specific view",

                "target": "sublimesocketpreference",

                "emit": "event_errorEmitted",

                "debug": true

            }

        }

    ],

    "replacefromto": {

        "view": "view"

    },

    "interval": 1000

}

->setReactor:

{

    "target": "sublimesocketpreference",

    "event": "event_errorEmitted",

    "selectors": [

        {

            "showAtLog": {

                "message": "Hello World"

            }

        }

    ]

}

->appendRegion:

{

    "view": "/Users/USERNAME/Library/Application Support/Sublime Text 2/Packages/SublimeSocket/SublimeSocketAPISettings.py",

    "identity": "03/12/13 18:46:17",

    "line": 10,

    "message": "herecomes daredevil",

    "condition": "keyword"

}



collectViews

STが開いているviewを収集し、kvsに保存します。


特にパラメータはありません。

SS起動時に自動的に呼ばれます。

→SS起動時に自動的に実行されるAPIは、SSパッケージ内の SublimeSocket.sublime-settings に記述されています。

"loadSettings" : ["collectViews"]


e.g. ST上で開いているviewを収集する。

ss@collectViews



runShell

SSからPythonを経由してシェルスクリプトを実行します。

bashなどの環境変数は引き継がれません。

main, delay, debug 以外の文字列 "-a" や "something" などは、 そのままコマンドラインで実行されます。

☆shell実行する都合上、value側に含まれるスペースを含む文字列 "a peaceful journey" などは、spaceが_に変換されます。

他にも、"[" -> "", "]" -> "",  "@s@s@" -> " " へと変換が発生します。

たとえばspaceを表示したい場合、SSへと入力する前の段階で、@s@s@ などに変換しておく必要があります。

これは " をエスケープして文字列を囲んだ場合でもきちんと発生します。


main[string]

コマンドラインの先頭に入る文字列です。


delay[int]

指定ミリ秒後に実行します。


debug

デバッグ用パラメータです。

セットされている場合はvalueに応じてデバッグ表示がSTのログに出力されます。


上記以外のkey[any]

value部分には、string, int, bool のほか、 JSONArray[any] の指定が可能です。


JSONObject形式で書いた場合、順がシャッフルされる可能性に注意してください。

また、key、valueともに、空文字の指定が可能です。


e.g. ruby gems "terminal-notifier"を実行します。文字列中のspaceは、_に強制的に変換されます。

JSONObject版 key value の内容が、コマンドラインのパラメータとして実行されます。key-valueペアの順は守られますが、ペア同士がどの順で記述されるかは未定義です。

ss@runShell:

{

    "main": "terminal-notifier",

    "-message": "\"Hello, this is my message\"",

    "-title": "\"Message Title\"",

    "-execute": "\"open -a 'Sublime Text 2.App'\"",

    "debug": true

}


JSONArray版 terminal-notifier -message "Hello,_this_is_my_message" -title "Message_Title" -execute "open_-a_'Sublime Text 2.App'" が実行されます。

ss@runShell:

{

    "main": "terminal-notifier",

    "-message": [

        "\"Hello, this is my message\"",

        "-title",

        "\"Message Title\"",

        "-execute",

        "\"open -a 'Sublime Text 2.App'\""

    ],

    "debug": true

}



broadcastMessage/monocastMessage

SSを介して、他のClientへとWebSocket経由でメッセージを飛ばします。

target

monocastMessageの場合のみ有効な、送付先のIdentityです。

inputIdentity を使う事で、Client側が自己申告できます。

実行時点でSS上に存在しないidentityを指定した場合、エラーが発生します。


message[string]

Clientへと送付される文字列です。


sender[stirng]

オプションです。

送付元の情報をidentifyする事が出来ます。

このキーがあることで、Clientへと到達する情報は、

senderのvalue:messageのvalue になります。


e.g.

ss@monocastMessage:

{

    "message": "here comes Daredevil! for only one",

    "target": "sublimesocketpreference"

}



showAtLog

文字列をSTのログに出力します。

主にユーザーへの通知や、動作確認に使用します。


message[string]

ログに出力される文字列です。


e.g.

ss@showAtLog:{"message":"Hello World"}


appendRegion

STで現在開かれている特定のviewへと、Region(四角形)を表示します。

情報はkvsのSUBDICT_REGIONS下に保存されます。 eraseAllRegions が発生したタイミングで、削除されます。


メッセージ情報他を埋め込むことができます。


view[string]

ファイル名を含むpathです。

フルパスが存在する場合、そのままviewを特定する要素として使用されます。

フルパスでない場合、適当に推測します。


最低でもファイル名.拡張子を含んでいる必要があります。

該当するviewがSTのview上に発見できなかった場合、”ss_f_noViewFound” Eventを発行します。


line[int]

Regionを表示する行番号です。


message[string]

Regionに保存する文字列データです。


condition[string]

Regionのカラーリングを決定するパラメータです。

STColor Schemeと連動しています。

SSでは、適当ですが、 keyword パラメータをError用、string パラメータをCaution用に使用しています。


e.g. ファイル /Users/USERNAME/Library/Application Support/Sublime Text 2/Packages/SublimeSocket/SublimeSocketAPISettings.py に対して、

10行目にRegionが表示されます。

1__#$!@%!#__スクリーンショット 2013-04-05 0.19.31.png

ss@appendRegion:

{

    "view": "/Users/USERNAME/Library/Application Support/Sublime Text 2/Packages/SublimeSocket/SublimeSocketAPISettings.py",

    "identity": "03/12/13 18:46:17",

    "line": 10,

    "message": "herecomes daredevil",

    "condition": "keyword"

}



runWithBuffer

SublimeTextでのファイル編集中のバッファを制御するために使用します。

他のAPIからviewを受け取り、そのviewのバッファに対して、ss_f_runWithBuffer イベントを発生させます。


view[sublimetext_view_instance]

SublimeTextのviewオブジェクトです。

インスタンスのため、APIから直に指定する事はできません。

e.g. 選択範囲が変更された際、現在のビューのバッファを ss_f_runWithBuffer イベントのReactorへと送付します。 

ss_f_runWithBuffer イベントのReactorがセットされていなければ何も発生しません。

ss@setReactor:

{

    "target": "sublimesocketpreference",

    "event": "on_selection_modified",

    "selectors": [

        {

            "runWithBuffer": {

                "view": "will be replace to specific view"

            }

        }

    ],

    "replacefromto": {

        "view": "view"

    },

    "interval": 100

}



notify

MacのNotificationCenterを起動し、任意の文字列を表示します。

スクリーンショット 2013-04-05 1.08.12.png

title[string]

タイトル用の文字列です。


message[string]

メッセージ用の文字列です。

"_"を" "(space)に勝手に変換します。


debug

デバッグ用パラメータです。

セットされている場合はvalueに応じてデバッグ表示がSTのログに出力されます。

e.g.

ss@notify:

{

    "title": "title-is-here",

    "message": "message-of-nyaaa"

}


補記: Linux、Windowsのことは考えずに作りましたが、下記サンプルでgrowlでの通知が可能です。

ss@runShell:

{

    "main": "/usr/local/bin/growlnotify",

    "-m": "message!",

    "-t": "Saved!",

    "-a": "\"Sublime Text 2\"",

    "debug": true

}



getAllFilePath

anchorに指定されたファイルを検索し、検索ヒット後、

ancorファイルがあるフォルダとその下のフォルダ内のすべてのファイルの絶対パスを,で連結した文字列をpathsに保持します。


anchor[string]

検索する対象のファイル名です。現在のSublimeTextのWindowBasePathを基準に、ファイルを上位階層へと探しに行きます。

特にリミットが無いため、間違えると永遠に上位フォルダへ検索の手を伸ばします。


header[string]

検索ヒット後、結果の文字列のfooterとして、pathsの前部に接続されます。


footer[string]

検索ヒット後、結果の文字列のfooterとして、pathsの後部に接続されます。


paths[string]

検索ヒット後、ヒット時のフォルダ以下にあるファイルすべてのpathを,で連結した、

header+連結済みpath+footer という状態の文字列を保持します。

e.g. readme.txtというファイルを検索し、そのファイルがあるフォルダ以下のすべてのファイルの絶対パスを,で連結した文字列をpathsに格納、

monocastMessageでクライアントへと送付します。

ss@getAllFilePath:

{

    "header": "header:",

    "anchor": "readme.txt",

    "footer": "footer",

    "paths": "will be entered"

}

->(paths|message)monocastMessage:

{

    "message": "replace",

    "target": "sublimesocketpreference"   

}

RESPONSE: header:/Users/sassembla/Library/Application Support/Sublime Text 2/Packages/SublimeSocket/tmp/preference.html,/Users/sassembla/Library/Application Support/Sublime Text 2/Packages/SublimeSocket/tmp/readme.txtfooter



readFileData

特定pathのファイルのデータを読み込みます。


path[string]

読み込み対象となるファイルのパス


data[string]

読み込んだデータが入力されます。


e.g. PythonSwitch.py というデータを読み出し、

monocastMessageでクライアントへと送付します。

ss@readFileData:

{

    "path": "/Users/sassembla/Library/Application Support/Sublime Text 2/Packages/SublimeSocket/PythonSwitch.py",

    "data": "will be entered"

}

->(data|message)monocastMessage:

{

    "message": "replace",

    "target": "sublimesocketpreference"  

}

RESPONSE: class PythonSwitch(object): def __init__(self, value): self.value = value self.fall = False def __iter__(self): """Return the match method once, then stop""" yield self.match raise StopIteration def match(self, *args): """Indicate whether or not to enter a case suite""" if self.fall or not args: return True elif self.value in args: # changed for v1.5, see below self.fall = True return True else: return False


eventEmit

独自定義のイベントを定義、発行します。

このAPIで着火できるイベントは、ユーザー定義イベントに限られます。


target[string]

Eventのターゲット指定に使用する文字列です。


event[string]

発行するEvent名です。 


e,g, MyTarget の event_MyEventというイベントに対するreactorをセットし、eventEmitでそのイベントを着火します。

ss@setReactor:

{

    "target": "MyTarget",

    "event": "event_MyEvent",

    "selectors": [

        {

            "monocastMessage": {

                "message": "eventEmit over.",

                "target": "sublimesocketpreference"

            }

        }

    ]

}

->eventEmit:

{

    "target": "MyTarget",

    "event": "event_MyEvent"

}

RESPONSE: eventEmit over.


openPage

SublimeTextと接続された状態のHTMLをブラウザで開きます。

HTMLはプラグイン内の tmp フォルダに、identity.htmlとして出力されます。


展開されたページは、SublimeSocket経由のmessageをログとしてHTMLに表示します。


Preferenceページの


identity[string]

展開されるページのWebSocketとしてのidentity指定です。

e.g. 06_10_13_14_32_08 というidentityを持ったページをブラウザで開きます。

展開されたページへは、monocastMessage, broadcastMessageでメッセージを届けることができ、HTML上に表示されます。

ss@openPage:

{

"identity": "06_10_13_14_32_08"

}



setWindowBasePath

SublimeTextで現在開いているファイルの位置を、SSのフォルダ検索の基準位置としてセットします。

ST2とST3で挙動が異なる(ST2だと非同期、ST3だと同期)


特にパラメータはありません。





Event Reference


各Eventについて、setReactor APIでReactorをセットする事が出来ます。

setReactorでcaptureできる各Eventが保持するパラメータについては、各Eventの項を確認してください。


SublimeText-Event

SublimeTextから発生するEventは下記になります。 発生タイミングなどの詳細は、同名のSublimeTextのAPI Referenceを参考にしてください。


on_selection_modified,  

on_pre_save, 

on_post_save, 

on_modified

これらのEventは、Reactorのinterval指定に従って発生判定を行っています。

一定時間内に複数回発生したとしても、最後に発生したEventのみが、intervalに合わせて処理されます。


REACTIVE_RESERVED_INTERVAL_EVENT = ["on_modified", "on_selection_modified", "on_pre_save", "on_post_save"]


Event params

すべてのEventが下記paramを発行します。

setReactorでは下記paramをreplacefromtoで転用可能。


view[sublimetext_view_instance]

SublimeText view


viewId[int]

SublimeText  view.view.id()


bufferId[int]

SublimeText view.buffer_id()


path[string]

SublimeText view.file_name()


basename[string]

os.path.basename(view.file_name())


vname[string]

SublimeText view.name()



SublimeSocket-Event

SublimeSocketから発生するEventは下記になります。

foundation series

emitEventなどでClientから発行することは不可能です。

setReactorに対して設定してください。



ss_f_noViewFound

appendRegion API使用時、該当のviewがSTのview内に存在しない = ファイルが開かれていない場合に発行されます。

発生したタイミングで、Reactorが反応します。



message[string]

view[string]

line[string]

condition[string]

パラメータはすべて、appendRegion APIへと入力された値が使用されます。

e.g. パラメータ例

{

    "view": "/Users/USERNAME/Library/Application Support/Sublime Text 2/Packages/SublimeSocket/SublimeSocketAPISettings.py",

    "identity": "03/12/13 18:46:17",

    "line": 10,

    "message": "herecomes daredevil",

    "condition": "keyword"

}



ss_f_runWithBuffer

runWithBuffer イベントの発生を受けて発生します。

runWithBuffer イベント発生時のviewパラメータを受け取り、バッファ上のデータをbodyパラメータに格納します。


target[string]

view[string]

body[string]

path[string]

パラメータはすべて自動的に入力されます。


e.g.  選択範囲が変更されると、そのビューのバッファの情報をbodyパラメータに格納し、monocastMessageでクライアントへと送付します。

サンプルとして、ファイル Default.sublime-commands を開いた状態で選択範囲を変更した際のRESPONSEを載せておきました。

ss@setReactor:

{

    "target": "sublimesocketpreference",

    "event": "ss_f_runWithBuffer",

    "replacefromto": {

        "body": "message"

    },

    "selectors": [

        {

            "monocastMessage": {

                "message": "replace",

                "target": "sublimesocketpreference"

            }

        }

    ]

}

->setReactor:

{

    "target": "sublimesocketpreference",

    "event": "on_selection_modified",

    "selectors": [

        {

            "runWithBuffer": {

                "view": "will be replace to specific view"

            }

        }

    ],

    "replacefromto": {

        "view": "view"

    },

    "interval": 100

}

RESPONSE: [ { "caption": "SublimeSocket: on", "command": "socketon" }, { "caption": "SublimeSocket: on > open preference", "command": "on_then_openpref" }, { "caption": "SublimeSocket: open preference", "command": "openpreference" }, { "caption": "SublimeSocket: status", "command": "statuscheck" }, { "caption": "SublimeSocket: off", "command": "socketoff" } ]





user-defined series

”event_”句から始まるユーザー独自定義のイベントを、emit パラメータがあるAPI経由か、emitEvent で発行することが可能です。

すべてのEventは、emit元が持つパラメータを持ちます。


e.g.

event_myEvent

event_emitHelloWorld

など、event_が付けばなんでもOKです。




saveなどのユーザー動作と組み合わせたEventの例

・setReactorでユーザーの on_post_save を監視

→発生時に動作するEventをselectorに定義


e.g. setReactorを使い、on_post_save Event発生時に、Hello World とSTのログへと出力します。

ss@setReactor:

{

    "target": "sublimesocketpreference",

    "event": "on_post_save",

    "selectors": [

        {

            "showAtLog": {

                "message": "Hello World"

            }

        }

    ],

    "interval": 1000

}




ユーザーによる範囲選択動作とRegionの選択を組み合わせたEventの例

・setReactorでユーザーの on_selection_modified Event を監視

→selector中で、containsRegions API をセット、

該当するview範囲に既設のRegionが含まれているかどうかチェックし、

適当なEventをemit


・setReactorで上記セットしたEventを監視

→selector中で任意の動作を行う


e.g. appendRegionで実際にRegionを発生させるサンプル。

on_selection_modifiedに反応するReactor内で、既設のRegionへの反応を記述。範囲がRegionを含んでいた場合、event_errorEmitted Eventを発行。

event_errorEmitted Eventが発行された場合、対応するReactorにて、showAtLogが発生する。

ss@setReactor:

{

    "target": "sublimesocketpreference",

    "event": "on_selection_modified",

    "selectors": [

        {

            "containsRegions": {

                "view": "will be replace to specific view",

                "target": "sublimesocketpreference",

                "emit": "event_errorEmitted",

                "debug": true

            }

        }

    ],

    "replacefromto": {

        "view": "view"

    },

    "interval": 1000

}

->setReactor:

{

    "target": "sublimesocketpreference",

    "event": "event_errorEmitted",

    "selectors": [

        {

            "showAtLog": {

                "message": "Hello World"

            }

        }

    ]

}

->appendRegion:

{

    "view": "/Users/sassembla/Library/Application Support/Sublime Text 2/Packages/SublimeSocket/SublimeSocketAPISettings.py",

    "identity": "03/12/13 18:46:17",

    "line": 10,

    "message": "herecomes daredevil",

    "condition": "keyword"

}




サンプルフィルタ

いくつか、サンプルのフィルタがあります。


TypeScript用のフィルタ

SublimeSocket/FilterSettingSamples/TypeScriptFilter.txt

tscが出力するログに対して、エラー行を表示しています。

すべてフィルタやReactorで書かれています。


API runSettingで読み込むとそのまま使える状態ですので、がんばってみてください。





wrote 2013/04/05 1:17:34

SublimeSocket + TypeScript ~さよなら! node.js強依存~ 編


概要

node.jsを貶める意図は無いです。


下記の続きです。

謎レシピ:TypeScriptのSublimeSocketフィルタ書いた



どーーーにもnode-tailの遅さに納得いかない。ファイルの更新拾うのが亀過ぎる

+

wsがOriginパラメータ持ってなくて大変めんどくさい

+

この2つのモジュールに依存するのどうなの? 残念なんじゃないの?


と思っていた昨今、

案の定、知り合いに使ってもらったら環境構築の時点でいろいろ躓いたので、

脱node.jsして、tsc以外のnode.js依存の部分を、すべてChromeのExtensionにおんぶに抱っこしてもらう事にしました。

俺の使い方が悪いんです。nodeはいいコです。


前提

・node.jsは結局使う

tscを内部で使っています。

よって、node.jsとtscがインストールしてある必要があります。


・Chromeに、SublimeSocket/tool内のExtensionをインストールしてもらう必要がある

nodeのwsとtailの代替になります。Developerモードでフォルダからインストしてもらう想定。

https://github.com/sassembla/SublimeSocket/tree/master/tool/chromeClient


・SublimeSocketが必要

はい。

現在0.8.5

https://github.com/sassembla/SublimeSocket



動画

百文は一動画にしかず

http://vimeo.com/63188211

TypeScriptのファイルを開いて編集するとエラー行が光ったり、エラー詳細がNotifyされたりする。

以前のようなコマンドラインでの入力がほぼ無いのがうれしい。


最初にlogファイルを作り出すために、touch使ってるけど。



スクリーンショット

同一フォルダに入っているところをフォルダ単位でコンパイルされ、クラス名の重複を怒られている時の図

スクリーンショット 2013-04-02 23.07.25.png



結果

最終的に、Chrome Extensionsで、nodeがやってた上記の内容をすべて肩代わりし、

かつ私的な科学の進歩でいろいろなことができるようになった。


・コンパイルにはtscを使用しているが、nodeとか一切表に出てこない

清々した。


一点、

tscが内部で node 表記でnode実行してるんだけど、Pythonからの実行だと環境変数が継げないので、参っている。

tsc自体に「どこのnodeを渡すのか」とかが指定できると良かったんだけど。

環境変数入れるところからのshellを作る事で解決した。

https://github.com/sassembla/SublimeSocket/blob/master/tool/chromeClient/tscshell.sh



・コンパイルモードが増えた

編集中フォルダのみをコンパイルするFocusモード、

対象のフォルダの中にある.tsをすべてコンパイルするFolderモード、

対象フォルダを含む内包物すべての中の.tsを見つけてきてコンパイルするRecursiveモード(未完どころか未制作)

から選べるようになるそのうち。今は内部の値で、直値でFolderモードに指定してある。

動画の中でもFolderモードにしてある。



・省エネ指向

コンパイル前後をフックする事で、Chromeでのtail自体の処理を、必要な時だけに絞ったりしてる。

SublimeSocketに動作設定を入力する際のファイルの、setReactorのあたり。

https://github.com/sassembla/SublimeSocket/blob/master/tool/chromeClient/TypeScriptFilter.txt


nodeでのtail時よりちょっと省エネです。でんちながもち。

、、、まあ、Chrome自体が、「これなんかめっちゃ電池喰ってないか?」と思う事はある。メモリも。


インストール手順

1.TypeScriptのファイルを適当なフォルダに用意します

スクリーンショット 2013-04-03 17.23.04.png


2.SublimeTextを入れます

(略)

tsファイルを開くとこんな感じです。シンタックスハイライトとかは、このへん がいい感じです。

スクリーンショット 2013-04-03 17.23.20.png

3.SublimeSocketを入れます

PackageControlには申請してないので、cloneして落としてください。ST3に向けて作業中です。

masterブランチそのままで良いと思います。

git clone https://github.com/sassembla/SublimeSocket.git


4.Chromeを起動して ChromeExtensionsにSublimeSocketChromeClient プラグインを追加

パッケージ化してないプラグインがSublimeSocketに入ってるので、インストール。

デベロッパーモードにチェックが入っていないと出ないので要チェックや。

スクリーンショット 2013-04-03 17.23.52.png

場所は、

/Users/ユーザー名/Library/Application Support/Sublime Text 2/Packages/SublimeSocket/tool/chromeClients/TypeScriptClient

TypeScriptClient フォルダを選んで、選択。


できた。 「ファイルのURLへのアクセスを許可する」 にチェック入ってるのを確認してくださいませ。

スクリーンショット 2013-04-03 17.20.20.png

5. .tsが置いてあるフォルダに、適当な名前でログファイルを作成する

コンソールで、

touch something.log

とかすれば良いと思う。日本語、スペースが含まれるファイル名はやめといたほうがいい。

スクリーンショット 2013-04-03 17.21.02.png

ここまでで準備完了。


作業する時は、ここから



6.編集したい.tsをSublimeTextで開いて、SublimeSocketをonにする

command + shift + p -> soon とか打てばOK

スクリーンショット 2013-04-03 17.25.19.png


7.  5で作ったlogファイルをChromeに喰わせる

スクリーンショット 2013-04-03 17.22.25.png

スクリーンショット 2013-04-03 17.24.52.png


8.SublimeSocketChromeClient プラグインをOnにする

a.png


☆6と8がこの順番に行われる必要があります。

6でサーバ起動、8でそのサーバに繋ぎに行ってるので。

つなげなかったら落とすとか今度入れよう。



準備完了

これでSublimeTextとChromeが接続されるので、あとは保存するたびにコンパイルが走る。

スクリーンショット 2013-04-03 17.25.38.png

STのコンソール開く (shift + control + `) と、いろいろコンパイル成功したよーとかエラーだよーとか表示される。

スクリーンショット 2013-04-03 17.26.18.png

エラー出す内容書いて保存すると、その場に表示される。 necomimiクラスなんか無い!!

スクリーンショット 2013-04-03 17.26.41.png

エラーは、赤丸のポッチをクリックすると、詳細をNotificationで表示するようにしてある。necomimi、スコープ内に存在しないってよ。

スクリーンショット 2013-04-03 17.26.50.png

以上。



構造

変なシーケンス図みたいなもので書くと、下記のような感じ。

tscのコンパイル結果をChromeがtailし、WebSocketでSublimeSocketに送付、

Errorの表示などを行っている。

STでの保存に反応して、コンパイルが走る。

スクリーンショット 2013-04-05 23.51.23.png



今後

プラグイン内で、結局 tscを使っているので、node.js に依存している。


node tscに依存せずにコンパイル、、、は、目指さない方がいいような気がしている。

なんだかんだ追従が面倒くさそうなので。


あと、フォルダ階層を潜りつつコンパイルするようにします。きっと。そのうち。



メモ

・ChromeExtensions側からWbSocketがcloseできない

SublimeSocketの既知のバグ。直す。

closeがSublimeSocket側に来ないんだよなー。WebSocketSharpのCloseはくるんだけどな。



・設定ファイルでいろいろセットできるようにしたい

コンパイルモードが3種あり、


モード切り替え を設定画面にもつ、、とかが出来ると思うんで、やろうかとおもってたんだけど、

localStrage使うしか無さそうで、とても面倒くさくなった。

コード内の値を直に書き換えると良いのでは。

https://github.com/sassembla/SublimeSocket/blob/master/tool/chromeClient/SublimeSocketChromeClient.js#L28



・そろそろrunShellをrunSeqShellとrunKVShellに分けないとなー。

SublimeSocketの中の不整合。

置換系の差が出るはず。バグとしてそのうち気付く気がする。

禁止文字replaceはかかってるので、その辺に追記すれば、、

⇒分けない方がいいって言われたなー。うーん。そだね。


なんかあれば、@toru_inoue まで。


wrote 2013/04/03 2:27:52

MacでNo GUI, No Dockなコマンドラインアプリケーションを作る


概要

コマンドラインアプリって何。

→コマンドラインから起動できるアプリです。


とあるアプリからとあるアプリへとMacのFocusを高速で移すアプリを作ったので、備忘録。


具体的な用途として、

Unityに他アプリで編集したコードのビルドをしてもらうためには、

UnityにFocusを移すのが一番、ということで、そういうMacのアプリケーションを作る話



成果

出来た物がこちらになります。

https://github.com/sassembla/SwitchApp



前提

次の条件を満たしたい。


1.一瞬だけFocusをUnityに移して次の瞬間別の任意のアプリにFocusを移す

→これでUnityビルドが走る。


2.コマンドラインから起動する

→最終的に完成した.app内のexec自体を、コマンドラインから起動する事を予定する。


3.コマンドラインから値を受け取りたい

→ある程度値をparameterとして渡せるようにしたい。

4.GUIを持たず、Dockにも表示されず、そのアプリケーション自体は一瞬もFocusを得ないようにしたい

→設定でなんとかなるのか?


5.確実に、100% "コマンドが順に行われる事" を保証したい

→以前コマンドラインから、open -a "アプリ名" などと行った場合、挙動の終了を待てず、挙動が安定しなかった。

そのへん改善したい。



1.一瞬だけFocusをUnityに移して次の瞬間別の任意のアプリにFocusを移す

まずFocusをあてるアプリをfromApp、次にFocusを当てるアプリをtoAppとすると、

このアプリ起動 > fromAppにFocus > toAppにFocus > このアプリ終了

とかすればいいので、はい。


Unityのアプリケーションの特性として、Focusがあたると既存のアプリのビルドを始めてくれるので、

それを狙って引き起こす。


MacのFocusを弄るAPIが複数見つかったので、試してみる。


ちなみに、コマンドラインツール っていうXcodeのテンプレートから作れる種類のアプリがあるんだけど、

それだと、純粋にCな感じで、Obj-Cの世界とかMacの世界へとアクセスするコードから書かねばならず、

とても辛かったので、MacのAppから実行する形を取っている。



2.コマンドラインから起動する

最終的にコンパイルした.appについて、

コンテキストメニュー >  パッケージの内容を表示 > Contents > MacOS > "アプリ名" っていうUnix実行ファイルが入っているので、

コレを使う。

スクリーンショット 2013-04-12 14.14.03.png

これを、コマンドラインから実行するのは、

exec ./SwitchApp $@


とかすれば、引数含めて渡して実行する事が出来る。



3.コマンドラインから値を受け取りたい

正直死にたい実装になった。もっとあるだろ。


NSApplication をextendsしたclass SwitchApp を定義し、main.mから実行される

int NSApplicationMain(int argc, const char *argv[]); メソッドをオーバーライド、


SwitchApp.h

@interface SwitchApp : NSApplication

int NSApplicationMain(int argc, const char *argv[]);

@end

①.m側で、appDelegateを自分で初期化し、Delegateにセット

        AppDelegate * delegate = [[AppDelegate alloc] init];


②argc と argv から、値を抽出し、

key-valueの形にして、appDelegateへと渡す。

        [delegate setArgs:argsDict];


③delegate側の- (void)applicationDidFinishLaunching:(NSNotification * ) aNotification メソッドを直で呼ぶ方法がなく、

アプリケーション自体の起動には

        [NSApp run];

を使うしか無い(遅延とかはできるんだけどNotificationの内容に干渉する手段はない?)っぽい。


②で値をグローバルな値として事前に渡し、[NSApp run]までの間、綱渡りしてるのが悔恨。

何か方法あると思う。


→runした後にメソッド実行して渡すっていうかそこから実行とかすればよかったですね!!!


4.GUIを持たず、Dockにも表示されず、そのアプリケーション自体は一瞬もフォーカスを得ないようにしたい

GUIナシ、Dockにも映らない設定のMacアプリを作るには、


Application is background only : UIを持たない

Application is agent (UIElement) : Dockや強制終了リストに映らない

をプロパティに宣言してビルドすればOK。


スクリーンショット 2013-04-12 13.50.43.png


詳細は下記

http://developer.apple.com/library/ios/#documentation/general/Reference/InfoPlistKeyReference/Articles/LaunchServicesKeys.html



5.確実に、100% "コマンドが順に行われる事" を保証したい

現在動いているアプリ一覧からApplicationのBundleIdentifierを取得し、activateさせる、みたいな方法があったのだが、

これが結局、ほぼ非同期でアクションを行っているようで、

2連続させると正常に動作しないことがあった。


一応下記のコードになる。 fromAppを文字列で定義してある。

NSString * fromApp = @"アプリ名";

NSArray * apps = [[NSWorkspace sharedWorkspace] runningApplications];

for (NSRunningApplication * app in apps) {

if([app.bundleIdentifier.lowercaseString hasPrefix:fromApp]) {

[app activateWithOptions:NSApplicationActivateIgnoringOtherApps];

}

}


for文の外まで各アプリを引っ張って、並べて実行しても、行単位でブロックするわけでは無いらしく、Focusの移る順が前後することがあったため、

10回に1回くらい、from to 2つのアプリのうち、toが全面に来ない、という事があった。


そこで、ScriptingBridgeを使う実装に変更。

id fromApp = [SBApplication applicationWithBundleIdentifier:fromAppStr];

if (fromApp) {

[fromApp activate];

} 

これで、Scriptの実行が完了するのが保証され、正しくfrom to の順にFocusが移り、toアプリが前面に残る結果になった。

かなり高速に動作するようなのだけれど、どうしても一瞬ちらつく。ぐぬぬ。まいいか。



以上。

wrote 2013/04/03 17:38:14

Breakが付いたUnitySublimeSocketAsset 0.6.1


概要

予定していた、ゲーム内パラメータをエディタで見る機能と、

Break(特定行でゲーム中断)という機能が、試験的に実装できた。

ホントホント。エイプリルフールだけど。


・ゲーム中のその瞬間のパラメータが見れる

Debug.Log("L行番号:ファイル名: ほか

Logの延長上で、ゲーム実行中の値が、エディタから見れるようになった。


・ゲーム中に特定の箇所でBreakが出来る

Debug.Log("B行番号:ファイル名: ほか

やはりLogの延長上で、特定Logが再生された瞬間、

無理矢理フォーカスをUnityから別アプリ(SublimeTextとか)へと移動する事で、

ゲームの挙動を停止させる。


その時の値も見れる。

スクリーンショット 2013-04-01 20.03.14.png



ムービー

https://vimeo.com/63078739



どうやってるのか

Unityで実行するLogに対して、特定フォーマットのものが発生したら、


UnitySublimeSocketがSublimeSocketへとデータ転送

→SublimeSocketが反応、値を保持

という事をしてるだけ。

設定には、SublimeSocketのAPIを使って、


->defineFilter: 

{

    "name": "unity",

    "patterns": [

        {

            "(.*)[(]([0-9].*?),.*[)]: error .*:(.*)": {

                "selectors": [

                    {

                        "showAtLog": {

                            "message": "groups[0]"

                        }

                    },

                    {

                        "appendRegion": {

                            "line": "groups[2]",

                            "message": "\"groups[3]\"",

                            "view": "groups[1]",

                            "condition": "keyword"

                        }

                    }

                ]

            }

        },

(中略)

        {

            "^L([0-9].*):(.*): (.*)": {

                "selectors": [

                    {

                        "appendRegion": {

                            "line": "groups[1]",

                            "message": "groups[3]",

                            "view": "groups[2]",

                            "condition": "string"

                        }

                    }

                ]

            }

        },

        {

            "^B([0-9].*):(.*): (.*)": {

                "selectors": [

                    {

                        "showStatusMessage": {

                            "message": "groups[2] break. line:groups[1], groups[3]"

                        }

                    },

                    {

                        "showAtLog": {

                            "message": "groups[2] break. line:groups[1], groups[3]"

                        }

                    },

                    {

                        "appendRegion": {

                            "line": "groups[1]",

                            "message": "groups[3]",

                            "view": "groups[2]",

                            "condition": "string"

                        }

                    },

                    {

                        "monocastMessage": {

                            "target": "unitysocket",

                            "message": "break"

                        }

                    }

                ]

            }

        }

    ]

}

正規表現に対して、特定のAPIを着火するようにしかけてあるだけ。


いやーAPIつくって良かったわー。


だいたいのことがカスタマイズできる。

思いつきで挙動変えられる。



まだ本決まりでないBreak

理屈は恐ろしく下らないものなので、お判りの通り、これは正しいBreakではない。

大体、Breakっつったら順に実行できたりしないとつまらないだろう。


今後、気が向いたらなんとかすると思う。

具体的にはコレ用のライブラリを書いて、Asset側で停止や次へ、を扱う。


行単位実行は、、たぶんやらない。行単位でBreak置いてください的な。


目指しているもの

本来、SublimeSocketは、Unity用では無く、Scalaとかをサーバサイドでコンパイルして、

そのコンパイル中継やパラメータの流れをクライアント=SublimeText側で受けることを目的としたものだった。

ライブコンパイル用のBufferも、WebSocketを基礎にした設計もその辺が根源にある。


なので、本来の用途じゃないけど、

なかなか、Unityとの連携は面白いなーと思っているところ。



そろそろAssetStoreに出す。出したい。誰かデバッグしてくれる人、追加で募集中。



関係ないけど

SublimeTextの設計思想、メイン機構はC++、プラグインはPythonで、っていうのが、

ほんともう素晴らしい。


プラグインはコンパイル無しの言語でサクサク書き、信頼が必要だったり頑強さが求められる部分や、テストは静的解析とかコンパイルできる言語で書くと

ほんとに良いと思う。


静的だけだとめんどい。 他に得に不満は無い。Scalaとか高機能な言語を使えば良い。

動的だけだとバグる。 テストの量がネックになる。 いつでも型を気にしないといけない。


この組み合わせは、とてもいい。

いやー捗るわー。



あっほら、4/1だから、アジだよ。


wrote 2013/04/01 19:52:11

退職しました #hogedriven 


概要

3月末日をもって、株式会社HOGEDRIVENを退職しました。


本来このような形で報告するのはとても心苦しいのですが、

今回の決断は一朝一夕で思いついたモノではなく、

悩みに悩んだ末の、本当に悩み抜いた結果の答えなので、しょうがないと言うか。はい。


ぶっちゃけ一身上の都合です。



なぜか

入社からのこの数年、何一つ不満はありませんでした。


何でも話せる気が置けない同僚、信頼できた上司、時々何言ってるんだろうコイツ大丈夫かな、と思った部下。

本当に離れるのが惜しい素晴らしい職場でした。



でもたった一つ、あの変化さえ無ければ、、そう思うものがあり、この決断に至っています。



すべてにおいて、カレーファースト

注意啓蒙すべき事柄として、少しバックグラウンドを書いておくと、

HOGEDRIVENはカレーに始まりカレーに終わる、そういう会社でした。

社食がカレー、は、この会社に入るのを決めるに足るメインファクターでした。

朝昼晩、カレーが無尽蔵に出てきます。夜食もカレーです。極めつけに、間食もカレーでした。



これが、美味しいんです。美味なのです。とても。



とくに @tan_go238 が入ってからの社のカレーへの傾倒っぷりは凄まじく、

素材選びの改革に端を発したクオリティの底上げは、時に社員に中毒者を出し、

本業のITタンポポのせ業の業績が怪しくなるほどカレーがおいしくなる、という素晴らしい環境でした。


まだあそこに残る友人たちの名誉のために言わせてもらうと、あの会社の福利カレー生は完璧です。



さらに、HOGEDRIVENの名に恥じぬ様々な駆動(焼き肉、スシ、シカ、ステーキ、鍋、寿司、ヤキニク、なべ、鹿、焼肉、おすし、ナベ、etc)

これらの人間の本能全開の駆動がなんと、社員なら5%OFFで参加できたのです。


鹿を○X△できたことも、あの会社ならではでした。


本業と全く関係のない食に関するイベントの企画力、発想力、実行力において、ぼくらは絶対に他社の及ばない、

業界、いや世界においても並ぶ者の無い、唯一無二の存在として輝いていました。


当時は断言できました。

その味に舌鼓を打ち、

「今日のキーマはキンッキンに冴えてやがるぜ、、ッ!」

とか言ってた自分がいうのもアレですが。


でも、

順調に思えていた会社に、変化が起こりました。



給料までカレーになりだした頃から、この会社はおかしくなった

全部上司であるDAIK、、おっと、、、大人げない。

特定の誰かが悪いとは思ってません。


でも、今まで社員のために動いていた組織が、いきなりトップダウンでカレーのために動くようになったのは、

自分にとって衝撃でした。



あの時の、上司であるDA○KSYさんの判断には、今でも疑問が残ります。


本当に正気だったのかな、とか。

せめて寿司だったらよかったのに、とか。


でもその時は、同時に、しょうがないかなーとか思ってました。

カレー美味しいですし。



でも自分の預金残高をみて、増えてなくて、

ああ、給与のすべてがカレーになったんだ、と実感したその時、ふと、思ったんです。






あ、カレー以外も食べたい。と。






最後に

そんなこんなで、

株式会社HOGEDRIVENを退職します。

ここまで書いて、だいぶすっきりしました。


ただ、あの日、自分を誘ってくれた上司Dさんの奢ってくれた一杯のカレー、、、

あれがなければ、今の自分はありません。


味への飽くなき追求、

辛さ=痛覚の限界へのマゾヒスティックなチャレンジ、

カレーにあったコメのために畑から現地調達するサバイバビリティ、

え、ソレ本当に必要なの?ってレベルの偏執的なスパイスへのこだわり。

特に、カレー口に含んでるのにわざわざ笑わせにくる @kiy0taka さん、

日に日に #カオスな鯛 の頻度が上がってく @backpaper0 さん、

途中からカレー特にインドのスパイスの話題しか振ってこなくなった @tan_go さん、


彼らとのクリエイティブな仕事は、

確たるカレー観が無かった自分に、今後ずっと考えの支えになるような「カレーの芯」を与えてくれたと思ってます。



さよなら、、!! カレーなるhogedriven



許可を得て、全員が映ってるアイコン画像をもらいました。

スクリーンショット 2013-03-31 23.53.10.png


こんだけみんなのアイコン並んでると、なんか泣きそうになりますね、、


今後、いまこの瞬間からすべき事

とりあえず、一つだけ決まってる事があるので、お約束でもあるし書こうと思います。







嘘だッ!!

ここまで読んでくれてどうもありがとうございましたッ、と俺は言うッ!!




wrote 2013/04/01 00:00:00

Unity用に、複数ファイルをmcsでコンパイルするだけの簡単なお仕事


概要

表題の通り

そろそろいろいろとDLLにして、ラクしようかなと思うところ。



参考

mcs(1) - Linux man page

http://linux.die.net/man/1/mcs



コマンドラインで

コンパイルしてDLLにしたいフォルダ上で、

mcs -r:/Applications/Unity/Unity.app/Contents/Frameworks/Managed/UnityEngine.dll -target:library -recurse:'*.cs'


以上。


こんな感じのフォルダで実行すると

スクリーンショット 2013-03-30 22.52.09.png

dllが出来る。 やったね!

スクリーンショット 2013-03-30 22.52.20.png

テストも無事通過したので、うれしい限り。




wrote 2013/03/30 6:48:06

UnitySublimeSocketAsset 0.5.4 テスト中みたいな


概要

引き続き、

UnityとSublimeTextを連携させるAsset UnitySublimeSocketAsset(USSA)を

テキトーに調整してる。



実行時のパラメータ値と、実行時エラーを表示

ついに字幕付きムービーになったわーい。

https://vimeo.com/62957311


実行時エラー系とかの表示につきあってたら、なんかBreakPointまでエディタ側で実装できそう。

特定条件でコードを停止させてエディタでコントロール、とか。



お知らせ

引き続き、USSAのテストとかつきあってくれるUnity使いの人募集中。

Mac + Unity + SublimeText使いたい(MonoDevelopに殺意を覚える)人向け。



ちなみに

SublimeSocketは特に言語や環境を限定してないので、

SublimeTextでこんな言語のコード書いてて似たような表示したいぜ、みたいな話があったら、是非

@toru_inoue まで。


たぶんどんな言語でも、実行ログ吐くならエディタ上に内容を表示できる。


wrote 2013/03/30 4:03:39

謎レシピ:TypeScriptSublimeSocketフィルタ書いた


概要

深刻に、やせようと思います。

関係ないけどTypeSciptのオートコンパイル & エラーをコード上に表示 君を書きました。


可能になるのは下記

・編集しながらの適宜ライブコンパイル

・保存に反応してのコンパイル

・エラー表示


やーエラーログ充実させないと辛いわ。

勉強になる。


やせたい。



実際の映像

https://vimeo.com/62707591



材料(ひとりぶん)

Sublime Text 2 :一個

SublimeSocket :一個

node.js :一個

wsモジュール :一個

tailモジュール :一個

TypeScriptソース :適量



レシピ


1.したごしらえ

nodeをインストールします。

最新のでいいんじゃないでしょうか。


TypeScriptをインストールします。

0.8.3でいいんじゃないでしょうか。

参考 http://www.typescriptlang.org


nodeのモジュールのws(WebSocketするやつ)

と、tail(ファイル監視するやつ) も、ここで入れてしまいましょう。

ws https://github.com/einaros/ws

tail https://github.com/forward/node-tail


wsモジュールは、もしかすると、Originを付けない駄目な状態かもしれないので、

その時はこっちを使ってみると良いかもです。

https://github.com/sassembla/ws


Sublime Text 2をインストールします。

長いので以降STと呼びます。

verは2で良いと思います。3の旬はまだ先です。

SublimeText http://www.sublimetext.com

SublimeSocketを下記から落としてSTのpackageフォルダに放り込みます。

ST内にWebSocketサーバ/STのAPIサーバを構築するプラグインです。

長いので以下SSと呼びます。

https://github.com/sassembla/SublimeSocket

TypeScriptのソース

各自入手するなり、自家栽培するなりしてください。

デモで使ったのは、 http://www.typescriptlang.org から持って来たGreeter.tsです。



2.STを起動、SublimeSocketをon

コマンドパレットからsoonとか打てば良いと思います。

正確には、SublimeSocket: on 。


これで、ST内にWebSocketサーバ/STのAPIサーバが立ち上がります。



3.node_tailsocket_typescript.jsをnodeで起動します。

nodeで、TypeScriptのコンパイル環境を立ち上げます。


その際、下記パスを使います。


・コンパイルしたい.tsファイルが置いてあるフォルダのパス

コンパイル対象になる tsファイルの検索条件は、単なる*.tsです。

複数ファイルをいっぺんにコンパイルしてますが、いまんとこ、異なるフォルダ階層のファイルは見に行ってません。

簡単に改造できる筈。


・node_tailsocket_typescript.jsファイルのパス

・tscwithenv.shファイルのパス

SublimeTextのパッケージフォルダ/SublimeSocket/tool/nodeTailSocket/下の下記2ファイル

(別フォルダへの持ち出し可、位置相関なし。 っていうかSTのパスがspaceを含むため持ち出しを強く推奨。)


これらをパラメータとして、nodeで起動します。


node node_tailsocket_typescript.jsファイルのパス tscwithenv.shファイルのパス コンパイルしたい.tsファイルが置いてあるフォルダのパス



SublimeSocketのフォルダパスをそのまま使って、Desktop上のフォルダ tscomp 内の.tsファイルを全部コンパイルしようとすると、

下記のようなコマンドになります。きっと。

node /Users/sassembla/Library/Application\ Support/Sublime\ Text\ 2/Packages/SublimeSocket/tool/nodeTailSocket/node_tailsocket_typescript.js "\"/Users/sassembla/Library/Application Support/Sublime Text 2/Packages/SublimeSocket/tool/nodeTailSocket/tscwithenv.sh\"" /Users/sassembla/Desktop/tscomp


第二引数の "\"/Users/sassembla/Library/Application Support/Sublime Text 2/Packages/SublimeSocket/tool/nodeTailSocket/tscwithenv.sh\"" について、

STのパスがスペースを含んでるクソッタレパスなので、""をつけ、かつ内部でも""がかかってる必要があるためエスケープしておく必要があります。


や、node_tailsocket_typescript.js と tscwithenv.sh を手近などこかにコピーして、平和に実行する事をお勧めします。



5.自家製TypeScriptをお好みで編集!

はっちゃけるところです。

好きに編集してください。

エラーがあれば怒られる筈だし、

編集したり保存したりするタイミングで

勝手にビルドが走ります。

コンパイルログが ・コンパイルしたい.tsファイルが置いてあるフォルダのパス に出力されるのですが、

でけーな邪魔だなーと思ったら手で消してください。

旨い機構とか考えたら自動的に消すとかしたいです。


全体像

・SublimeText内でSublimeSocketを起動、WebSocketを通じてSublimeのAPIを実行可能に。

・nodeで、TypeScriptのコンパイルログを監視、結果をWebSocket経由でSublimeTextに転送。

・SublimeText側でエラーとか行とか内容を取得、表示。

・SublimeText側から、コードの編集や保存をキーに、コンパイルを実行。


ということをやってます。



ところで痩せたいです。運動スルベ。

wrote 2013/03/25 17:04:21

Unity 4.1でも性懲りも無くXcodeから作ったプロジェクトで起動してみる


概要

モジュールのテストとかは、Xcodeで行いたい所存。

テストが完了したらプラグイン化すればいいのだし。

開発速度と繰り返しと苦楽の問題。



Unity 4.0からの変更点


結論からいうと、


・Unityの起動を任意のタイミングにすること→×

・UnityとARCライブラリとかを共存させること→○

・XcodeからOCUnitとかテストを走らせること→○


4.0で可能だった恐ろしいチートのみが不可能になった。正しい。



内容と経緯

4.0の時は、手製の設定でもって、Unity for iOS を

Xcodeで作成したプロジェクトから実行する事が出来た。


好きなときに好きなUnityプロジェクトを起動したり、

XcodeでのObjective-Cのテストなどが可能だった。


参考: UnityのiOS向けビルドを別アプリに含んで起動する

Unityを自動的にビルドする設定にしたときのメモ



が、これが4.1から不可能になった。

UnityのアプリケーションをiOS中から起動すると、Unityの初期化処理中にエラーで落ちる。


もっとも、「穴だったから封じた」的なものではなく、

プロファイラを充実させる過程で、スレッドの数に注目するようになり、

その結果として、チェック機構のalloc過程ですでにthreadが存在する場合、mutexでエラーが起き、

Unity起動中に落ちるようになった、というのが真実っぽい。


Assertionで吹っ飛んでる節もないので、対策としていれた、と言うよりは、

取得して来たデータを変更しようとして、すでに存在してるthreadとぶつかってるような印象。


ま、なんにせよ、試験目的を果たしたプロジェクトが、アップデートで使えなくなった、

という状態に変わりなく。 それはそれでいい。正直好き放題出来すぎてた。



たぶんがんばれば突破できる。

でもがんばらない事に決めた。 テストする方法は残ってたから。



というわけで代替法

1.Xcodeで新規プロジェクトを作成 ARCありでOK

2.設定を調整(ぶっちゃけ以前の UnityのiOS向けビルドを別アプリに含んで起動する の構成がそのまま使える。)

3.Unity出力物をプロジェクトにぶち込む(-fno-objc-arc付与しまくり)

4.main.mをmain.mmに書き換え、ARC使わない設定に変更(-fno-objc-arc付与)、Unity出力物のmain.mmを模倣。


つまり、KSUnityConnectorから接続していた部分は無かった事にする


何かARCを使う部品が存在する場合、

Unity出力物の Classes/AppController.mm の startUnity 関数に書き足すと良いと思う。

調子乗りすぎるとやっぱり怒られるけど。



メリットの移り変わり

これでもまだメリットにまみれていて、

XcodeでUnityプロジェクト自体のテストが実行可能。

つまり、Jenkinsなどでの自動テストに関しては、まったくメリットが失われていない。


デメリットは、どこまでいっても「標準のやり方ではない」事。


自動テストが良いとこまで来たら、プラグイン化して、やっぱり人力でデバッグしような! ケースを作るのは人間だ!

デバッガとかそういうのは仕込みまくる前提で。


自動で出来るフェーズが存在するだけで、やり直し速度が格段にあがる。

なにより自動化できるわけですし。おすし。



すしくいてえ。

wrote 2013/03/20 20:52:39

Unityにスクリプトのコンパイルを依頼するためにどう土下座すれば


概要

Unityで、他のアプリケーションと連携して、特定条件下でビルド/Playを走らせてほしい。

具体的には、デフォのMonoDevやXamarinやSublimeTextなどの外部エディタから、コンパイルを走らせたい。

編集しながら、一定のタイミングでビルドを走らせたい。

オートコンパイルがやりたい。


ビルドのトリガーは、Unity Editor側でも、外部エディタ側でもかまわない。

今は、外部エディタからの制御を可能にしたので、そこからの入力を前提に考えている。



特定条件

求める条件は下記の通り

1.エディタでのファイルの保存、ビルドトリガーの実行(⌘+bとか)をトリガーに、Unityが信号を受け取る

2.トリガーをきっかけに、Unityがビルドを行う

3.Unity以外のアプリにフォーカスが当たっている状態でも発動する

4.Unity.appは起動し、特定のプロジェクトを開いている

5.Unityとエディタは同一マシン上にある


上記条件のうち、1だけはそれ用の機構が必要なので、作った。

エディタの特定動作から、UnityEditor側にトリガーを送り、UnityEditor側もそれを受けることができる。


で、難関なのが、2だった。



実現手段その1

Unityのビルドは、UnityEditorなどの中で、特定のスクリプトを実行すればOK。

EditorApplication.isPlaying = true;


とか。


が、これには制約があり、


制約1.このメソッドは、UnityのmainThreadからでないと実行できない

制約2.今回は外部からの入力という事で、別プロセスでUnityEditorから実行することになるので、実行母体はstaticなScriptになる

制約3.入力経路の関係上、Unityでトリガーを受け取る部分はmainThreadではなく、subThreadになる

制約4. Editor上で、subThreadからUnityのmainThreadに合流するAPIとかすべは無い??(見つけられてない


mainThreadでの動作は、UnityEditorのツールバーとかからクリックで選んだら即OK、なんだけど、、

唯一、

Concurrency kit 

C♯3.5以上の環境で動く、Taskっぽいものが実装してあるAsset

http://u3d.as/content/spicy-pixel/spicy-pixel-concurrency-kit/312


テラシュールさんの判りやすい説明(まるなげ)

http://terasur.blog.fc2.com/blog-entry-341.html



が、対今回の用途として凄くいいとこまで行ってるんだけど、制約2 Editorのスクリプトがstatic前提 のため、

肝心なところでエラーが出る。


具体的に書くと、taskFactory.StartNew(Createobject()); が、taskFactoryがstaticじゃないので利用できずに詰む。


このライブラリはstatic前提で書かれていないんだわー。 だわー。ゎ_. →ちゃんとAPI読んだらそんなことないかもしれないよ? って言われたので後で読む。

→ここから派生する別の解決策として、Unityにフォーカスが当たっていないタイミングでも定期的に動き続ける

UnityEditorのフックを探す、という手も考えられるんだけど、そんなの無さそう。見つけられてない。


実現手段その2

ほかの手段として、

Unityのバッチを使用する手段も有るんだけど、こちらにも問題がある。


下記のようにUnityのプロセスをバッチを介して動かせるが、

/Applications/Unity/Unity.app/Contents/MacOS/Unity -batchmode -executeMethod BuildBatch.Build

とか。主にCI上で利用している。-quitで毎回終了させる事もだいじ。


これが動くためには、Unity.appがバッチ内容の対象のプロジェクトを開いていない 必要がある。 条件4への明らかな違反。


無視して動かそうとすると、「ちょwwなんか既に起動してるんですけどwww」なエラーを吐く。 ファーーーーーーwwwww


こんなエラー。

Aborting batchmode due to failure:

Fatal error! It looks like another Unity instance is running with this project open.

Multiple Unity instances can't open the same project.


今回の用途としては、実行したり編集したりしながらビルドしたいので、詰んでる。Unity起動してないとすぐ遊べない。

→対象となるプロジェクトを設定したらどうなるん?

駄目でした。 Unityは全く悪くない。俺が変な事しようとしてる。 先生ー! 俺君がへんなことしてます!



妥協の上での実現手段

いまのところ、下記2つの手段で、実用レベルとして妥協しまくりだが、実現している。


手段1.保存時トリガーをUnityが自動検知してビルドするのを利用する

Unityからファイルを開くと、エディタでのファイル保存時にビルドが走ってくれる。

Macのファイル監視イベントをつかってるっぽい。


→Unityが変な開き方するので、だいぶ辛い。一回で検知しないことが稀によくある。


多分、汎用化のために、


1.アプリケーション起動コマンドを実行

2.そのアプリケーションにファイルパスを渡す


とかを行ってるんだろうなーと思うなど。

それにしても認識しない。最初の一回は絶対に認識しない。 なによりシングルファイルで開いちゃってとてもダサいので逃げ出したい。



手段2.Unityにフォーカスが移った瞬間ビルドが発生するのを利用する

一瞬だけUnityにフォーカスを持って行くことでも自動的にコンパイルが走る。

っていうか現在、一番まともな代替手段がコレ。


→やってみたところの動画

https://vimeo.com/61986887


保存をトリガーにしていて、ファイルを保存するとパパッとフォーカスが移動して、、、つらい、、、、

なにかの宗教的儀式みたいだ、、 なにかの宗教的儀式に従事されてる方すいません、、


上記を満たす実行可能手段を探しています

たすけてください! たす、、け、、


wrote 2013/03/17 13:53:03

Jenkinsによく入れるものリスト


概要

Jenkinsのセットアップを適当にひとんちとかでする機会が増えたんで、

コレみて入れろ的なことがしたくなりメモるなど


ビジュアライザの系統はものすごくたくさんあるし選んでいれてるけど、

必須な指標はプロジェクトごとに異なるので紹介パス。



Git Plugin

Gitのプラグイン

https://wiki.jenkins-ci.org/display/JENKINS/Git+Plugin

このくらいはデフォルトで入っててほしいところ。



Jenkins Multiple SCMs plugin

バージョン管理系プラグイン

https://wiki.jenkins-ci.org/display/JENKINS/Multiple+SCMs+Plugin


バージョンが低くてちょっと困惑するけど、

安定してるしデフォルトで入っていてもいいのでは。

要Git Plugin。


複数リポジトリの結果を順に出し分けたり、

Git Plugin単体ではできないような事も出来るので、便利。



Jenkins Gradle plugin

Gradle用のプラグイン

https://wiki.jenkins-ci.org/display/JENKINS/Gradle+Plugin

gradlew使うとかの簡単なwrapperも選択できるので、

使うとgradleを使ってのビルドがちょっと楽になる。



Jenkins Unity3d plugin

Unityのビルド用のプラグイン

https://wiki.jenkins-ci.org/display/JENKINS/Unity3dBuilder+Plugin

ビルドがラク。


ほんとに基本的な奴だけになった。

wrote 2013/03/14 18:11:58

Macで、コマンドラインからなんか通知を出す


概要

通知を出したくなった。

こういうの。 Macで。 できればWindowsでも動く奴が好ましい。

スクリーンショット 2013-03-11 16.32.49 1.png



Growlに通知を出す

もうときめかないけど、Growlから出す。



Pythonからinできる仕掛け

GrowlNotifyを使う。

http://www.growl.info/downloads



SublimeTextから叩くコードのお手本みたいなのあったラッキー

https://github.com/flxfxp/My-Stuff/blob/master/Sublime%20Text%202/Plugins/growlnotifier.py



おまけで、WebSocketClientなものもあった。

http://pastebin.com/9938RAEE



サクッとだせた

/usr/local/bin/growlnotify -m message! -t Saved! -a "Sublime Text 2"

1__#$!@%!#__スクリーンショット 2013-03-11 16.32.49 1.png

やったねたえちゃん!


Growlではアプリケーション立ち上げるとかサクッとは出来ない

Notificationをクリックしたときに、別のアプリケーションにフォーカスするとか、

立ち上がるとかやってほしかったんだけど、


GrowlNotifyからはそういう事できないみたいだ。

そうか、、、(Growlをアンインストール)

ろくに貢献もしてないのにごめん、、、ごめんよ、、、



NotificationCenterに通知を出す

Mac限定ここに極まる。



RubyGems使うと簡単だった

特にオープンにCLIとして用意されていない、という事実。

http://osxdaily.com/2012/08/03/send-an-alert-to-notification-center-from-the-command-line-in-os-x/


よって、下記を使わせてもらう事にした。

https://github.com/alloy/terminal-notifier



インストールして実行

terminal-notifier -message "Hello, this is my message" -title "Message Title" -execute "open -a 'Sublime Text 2.App'"

スクリーンショット 2013-03-11 20.22.49.png

でましたわー。

クリックでコマンドラインの実行も出来た。


でもMac限定が強過ぎる上に、NotificationCenterってMac自身がガンガンつかうので、

本格的な利用(って何)を考えると選べないな。


開発用に使いたいので、日常の用途と混じるとつらい。



上記が実行できるサンプルをSublieSocketに投入してみた

テストコンソールから実行すると、ブラウザ -> SublimeSocket -> NotificationCenter と連携して、Notificationが出る。

test.png

以上。



wrote 2013/03/11 10:53:31

過去にGradleで書いたプロジェクトまとめた


概要

ちょっとまとめつつ。

現在も公開しているものに限る。

逆に言えば公開時の風味を可能な限り残してあり(ry



ScalaのビルドをGradleで(2.9だ多分ガハハハ)

https://github.com/sassembla/SampleScalaGradle



AkkaのRemoteActorをGradleで

https://github.com/sassembla/ScalaAkkaRemoteActorWithGradle



Specs2のJUnit連携をGradleで

https://github.com/sassembla/ScalaSpecs2WithGradle



githubとかにMavnRepoライブラリ上げる設定をGradleに書く

https://github.com/sassembla/SampleMavenRepoByGradle



上記を使う

https://github.com/sassembla/SampleGithubRepoUseProjectByGradle



最新にしたかったらプルリクしてくれ。




wrote 2013/03/09 17:45:41

バッドノウハウとは何だろうメモ


概要

自分が考える「バッドノウハウとは何か」まとめる。



バッドノウハウ a.k.a ただの残念

本来動くはずの実装に対する残念なバグを回避するための手段、実装。


たとえばガラケーの時は、端末ごとにサウンドプレイヤーの特性が~とかで、

APIは一辺倒なんだけど実挙動が違うとかあり得た。死ねば良いし実際死んだので文句は無い。

これをこじらせたのがAndroidで、APIとかスペックとかドキュメントに書いてある通りに

動かないことが稀によくある(悪意のある誇張

そこで、いろんな機種でも動くように、まあいろいろ錯誤するわけですよね。

その結果動くからそうね。良かったじゃん。


この努力はブラウザでもネイティブでもずっと今後もあるから、がんばれバッドノウハウ。(この項は改変されました)



CSSとかだと、reset.cssがバッドノウハウの域だと思う。超使ってたんですけど。

最近はこういうのがいいらしい (自分では使ってないけど職場で使ってる)

選択肢が生まれてバッドノウハウに降格的な。


[なぜリセットではなく Normalize.css を使うのか]

http://yomotsu.net/blog/2013/02/23/normalize.html



バッドノウハウ a.k.a Blocker、未来殺し

将来変更性に対するBlockerになり得る悪手。


例えば多方面に影響を与える状態値を末尾に持ってしまったり、

きちんとした上位設計をしない事で、

未来そのパーツや全体が持つ変更可能性とか修正可能性を奪い去ってしまうこと。

主犯を挙げるとこんなキーワードが出てくる

・アホなextend

・広範囲に及ぶ独自型のアホな乱用

・状態の下手な隠蔽

・プラグインなど、変更可能性が多い場所でのjarなど固定化(これはピンポイントにMavenをDisっていると思ってもらってOK)

・上記から産まれる密結合


症状としては、変更が大変。大変。



自分、疎結合大好きなんですが、


上記みたいな問題が出るのを、可能な限り遅らせることができる(主観です)

+

可能な限り修正を楽にする事が出来る(主観です)

ので、疎結合大好きです。



思うに、jarとかlibとかsoとかのライブラリはライブラリではなく、ファンクションとかそういう名前の方が良かったのでは。


x Library

o Function

そういう意味で、現代にはActorが居るのだと思っている。

Actorをクライアントサイドのコードで使ってみると良い。 すばらしいですよ。

全部Actorの海に沈むけど。



バッドノウハウ a.k.a 言語内言語機能拡張

言語機能自体を自己的に拡張する試み。


JavaScriptを使ってのFWに頻繁に出てくる。


何が悪いかと言うと、どこまでがその機能のための実装なのかどこからがその機能を使った実装なのか、という

断面の喪失に繋がる


例えば機能Fを言語Jに実装するとして、

言語Jで書く必要が有るわけで、、、

どこまでがその機能を実装するための実装で、どこからがソレ以外か、いつまで判然としてられると思う?っていう、

局所性の明示が自明に出来ないところが生まれる。


これが、損のはじまり、ここではこの種類のバッドノウハウの入り口だと思っている。

人間によるidentificationが必要、って時点で、もう駄目のエントリーポイントに立ってるんだとおもう。

で、

ここでドキュメンテーションが出てくる。モジュライズしようぜみたいな話がでてくる。

FWにしよう、1層限定のextendを使おう、など。


実利として、これらは効果があると思う。

でも、そもそも無くてすむ方が良いだろ、、、と思ってしまうんだけど。そういうのは甘えですかそうですか。



一度失った断面を取り戻すのはとても大変で、隅々までそれ全体を理解しないと、恐ろしい深度で実はつながってたりする。

時間が経つほど地下茎は全体に行き渡る。


再設計とか書き直しとか、こ、こんな機能の貧弱な言語でやってられるか! 俺は別の言語で書くぜとかそういう部類の所行が必要だと思う。



JSに関しては、そこでaltJSですよ、っていう。





なんかバッドノウハウっていうより悪手コレクションになった、、みたいな、、ああ一緒か。


wrote 2013/03/06 13:52:00

UnityのMenuItemに罫線をつける、15分くらいの残念な歴史 ~完結編~


概要

自作プラグインのメニュー書いてました。


で、内容も纏め終わってて、出来る事も判ってきたので、えっと、

罫線<hr>これを、項目と項目の間に表示したかったわけです。



完成品

出来上がったものがこちらになります。

スクリーンショット 2013-03-05 21.11.59.png



このへんを参考にしたんです

http://docs.unity3d.com/Documentation/ScriptReference/MenuItem.MenuItem.html


大丈夫! 公式のサイトだよ!



B.C. 10分 可/不可、誕生

で、こんなコードを書いてました。

[MenuItem ("SublimeSocket/connect")]

static void Connect () {

}

[MenuItem ("SublimeSocket/connect", true)]

static bool IsConnectable () {

return false;

}



[MenuItem ("SublimeSocket/close")]

static void Close () {

}

[MenuItem ("SublimeSocket/close", true)]

static bool IsClosable () {

return false;

}


これで、

connect と close の2つの項目が、disabled状態で表示されるはずです。

こんなふうに。

スクリーンショット 2013-03-05 22.05.59.png


B.C. 0分 過ちのはじまり

まず、この修飾メソッドの使い方がアレだった。


[MenuItem ("SublimeSocket/connect")]

で、SublimeSocket 項目をメニューに表示、

クリックするとconnectとcloseが表示されますよ、と。

直下のメソッドは、connectとかが押されたときにfireされる。


で、じゃあすぐ下のペアはなんなの?っていうと、

パス部分の名前が一致する、すぐの修飾されたメソッド に対して、eneable/disableを設定する関数+修飾

なるほど。

違いは第二引数、true の存在。

[MenuItem ("SublimeSocket/connect", true)]

この値と一致する値を直下のメソッドが返す場合、その項目はenable

逆ならdisable


そういう仕様。

なるほど。へんなの。。。


A.C. 5分 そして罫線へ、、

で、とりあえず作ったわけですが、


けいせんほしい。

けいせんほしい。

priorityというパラメータがあるんだぜ、ってことで、まず調べる。


Separator in custom Editor MenuItem

http://answers.unity3d.com/questions/51906/separator-in-custom-editor-menuitem.html

ほう。

で、

こうしてみた。


[MenuItem ("SublimeSocket/connect")]

static void Connect () {

}

[MenuItem ("SublimeSocket/connect", true, 10)]

static bool IsConnectable () {

return false;

}



[MenuItem ("SublimeSocket/close")]

static void Close () {

}

[MenuItem ("SublimeSocket/close", true, 20)]

static bool IsClosable () {

return false;

}

1__#$!@%!#__スクリーンショット 2013-03-05 22.05.59.png

しーん、、、、


え。線が入らない。 値を変えても変わらない。 そんなアホな、、

priority値をどんなに変えてもだめ。  


いえね、罫線入れるとかはオプション側かなって思い込んじゃった。


過ちの始まりだった。



A.C. 10分 サルの惑星 ショート・ショート

じごくの はじまりだ!!

1stバッター・ハイフン

スクリーンショット 2013-03-05 20.47.25.png

うんうん、なんか切り取れそう





2ndバッター・アンダースコア


スクリーンショット 2013-03-05 21.01.06.png

ここで判明する、「同じ文字列で同じ長さ=同じ項目なので対消滅する」という

至極真っ当なルールが追い打ちをかける。

つまり長さが違う。 いやだ。。。。。



別の文字で同じ長さ、、そうだ!!




3rdバッター・オーバーライン

これだ! →‾‾‾‾‾‾‾‾‾‾‾‾‾   t‾wadaさんみたいな救世主だ!!


スクリーンショット 2013-03-05 21.03.57.png


もうね、腹抱えて笑った。


アホかと。さすが俺、アホかと。



A.C. 15分 ジャッジメント・デイ

ここで、4番が仕事をします。


[井上さん、できましたよ]

スクリーンショット 2013-03-05 22.47.05.png


俺「え。」


コードがこちら。


[MenuItem ("SublimeSocket/connect", false, 10)]

static void Connect () {

}

[MenuItem ("SublimeSocket/connect", true)]

static bool IsConnectable () {

return false;

}



[MenuItem ("SublimeSocket/close", false, 30)]

static void Close () {

}

[MenuItem ("SublimeSocket/close", true)]

static bool IsClosable () {

return false;

}


え。


オプションじゃないほうに入れんの。

引数足りないのに。


つまり第三引数に入れろと。


無理矢理第二引数を埋めて入れろと。


(えー、、、、、、、、)



声にならない声



出来上がったものがこちらになります。

1__#$!@%!#__スクリーンショット 2013-03-05 21.11.59.png



Undocumented information

罫線の発生条件は、

直前のpriorityとの差が11以上


11以上



ハイここテストに出すぞ。



priorityを1から始める場合、


[MenuItem ("SublimeSocket/connect", false, 1)]

static void Connect () {

}

[MenuItem ("SublimeSocket/connect", true)]

static bool IsConnectable () {

return false;

}



[MenuItem ("SublimeSocket/disconnect", false, 2)]

static void Close () {

}

[MenuItem ("SublimeSocket/disconnect", true)]

static bool IsClosable () {

return false;

}



// reload

[MenuItem ("SublimeSocket/reload", false, 13)]

static void Reload () {

}

[MenuItem ("SublimeSocket/reload", true)]

static bool IsReloadable () {

return false;

}



[MenuItem ("SublimeSocket/autoConnect-on", false, 24)]

static void TurnAutoOn () {

}

[MenuItem ("SublimeSocket/autoConnect-on", true)]

static bool IsTurnableAutoToOn () {

return true;

}


みたいになる。

たぶん、罫線出る == (10 < distance) とか書いちゃったんじゃねーかなー。 



次回予告

チェック∨ を探す旅に出ます。

こういうのです。


スクリーンショット 2013-03-05 22.13.01.png



正直、














むりっぽい気がしています。













からの、








不明.png

nakamura001

@toru_inoue チェック付けるのはPrime31ですらこんな実装なので結構難易度高いんじゃないかと見てます http://t.co/qM1cWOSomL















、、、、、、


、、、、


、、



よし!!









打ち切りました。

俺さんの次回作にご期待ください。






wrote 2013/03/05 21:53:45

Unityのプラグイン開発でテスト書く


概要

Unityのプラグインをちまちま作ってるのですが、

プラグインについてのテストを簡単にやる方法思いついたので備忘録までに。

こんな感じになった。


gist

https://gist.github.com/sassembla/5082797



Purpose

特定のタイミングでプラグインの特定のメソッドを走らせて、状態をチェック。


[InitializeOnLoad] を使って、

Unityが自動実行するたびにそれっぽいことを行えば、小気味よく実行できる。OK。


なんでこんな簡単なこと思いつかなかったんだろう。



いろいろ条件

・Editorフォルダにファイルを置く

Unityルール。InitializeOnLoadはEditor用。

・Assert関数は手書き

UnityにはAssert無い。



完成したときの環境がこちら

UnityのAsset下にEditorフォルダつくって、

gistに上がってる内容を、UnityEditorTestKit.cs と言う名前でcsharpファイルとして保存すればOKです。


スクリーンショット 2013-03-05 16.53.17.png

スクリーンショット 2013-03-05 15.18.23.png

これだけで、Unity上のファイルがコンパイルされたりPlayするたび、テストの中に書いた内容が動くようになります。

エラーが出るような内容があれば、Exceptionが発行されます。


いやー書き続けられるって素敵だわー マジで素敵だわー。



えっ、、終わり、、、?

Q.[test]Prefixとか、Annotation付けて検出とかは?

A.そういうのが出来る星でがんばってください。

もしくはプルリクするなりがんばって作ってAssetStoreに出すなりするんだ!



Q.どのテストが成功したかとかは判んないんですか?

A.ぁあ~、、 判らないっすねぇ~、、


→個別のテストの識別子とかはとりあえず考えてないので吊ってきます。

辞書持つとかすれば出来るんですが、、、めんどい。

今のところは、Debug.Log("これでひとつよろしく");


→出力は、CIに入れる事があったら、xmlでも吐くようにします。

YAGNI! YAGNIダヨ!!

wrote 2013/03/03 19:16:56

ネコハッカソンいってきました!


概要

コレです。

http://willcat.doorkeeper.jp


まとめ

論よりネコ

写真 2.JPG

この世の英知が詰まったイベントの神々しい風景



写真 1.JPG

時に慰め、時に無視。 アロイに砕かれたこころも繊細に癒してくれます。



正直幸せすぎていっさいのきおくがありません。


ネコは見ています。

ネコと和解しましょう。


wrote 2013/02/25 0:23:18

WebSocket-sharpを使う


概要

これ

https://github.com/sta/websocket-sharp

を使ってみる。



使い方

dllになっているので、そのまま放り込んで使うだけっぽい。


めんどくさいので、exampleの中の、Releaseをいきなり使ってみた。

→固まってUnityごと落ちた

→usingの中で使っていたので、using抜けるタイミングで切断されてただけだった。



iOSビルドに巻き込む際の注意点

入れる事と使う事は出来た、が、そのままだと、iOS向けビルドにつっこんだタイミングで、

System系の変換不可なライブラリを含んでいて面倒くさい。

なおせるもんならなおして、プルリクしようと思う。

きっといつか。


いちおう気づいた注意点

このライブラリ、サーバに繋ぎに行って、onOpen呼ばれるより先にSendしても

何のエラーも吐かない。


や、そんな常識知らずのこと、するほうが悪いんだけど、

Assertionあると馬鹿も出来ないから良いよね、って思うなど。


failsafe的にどうなんだ。


あと、Originがついてない。

チェックするのに使えるので、付けようぜ。


フォークして、付けた。

https://github.com/sassembla/websocket-sharp


iOSビルドとかも可能になったら、更新すると思う。


wrote 2013/02/22 19:29:46

SublimeSocket0.8.0で出来るようになった事まとめ


概要

普通に開発に使う分には、いろんな機能が整った。

メモ程度に。



フィルタがJSONで追加可能

ss@defineFilter:

{

    "name": "unity",

    "patterns": [

        {

            "[(]([0-9].*?),.*:(.*)": {

                "runnable": {

                    "showLine": {

                        "line": "groups[1]",

                        "message": "groups[2]"

                    }

                }

            }

        }

    ]

}


みたいに書けるようになった。

後出しでどんなフィルタ内容にも対応可能。


リアクタの追加

SublimeTextの特定のイベントを監視、一定インターバルで指定APIを実行可能になった。


ss@setReactor:

{

    "target": "targetWebSocketClientIdentity",

    "event": "on_selection_modified",

    "selector": {

        "playRegions": {

            "view": "will be replace to specific view",

            "target": "targetWebSocketClientIdentity",

            "showatstatus":true

        }

    },

    "replacefromto": {

        "view": "view"

    },

    "interval": 100

}


イベントから予約済みAPIへのパラメータ代入を実装したけど、うーん名前がわかりにくい。

replacefromtoとか。これからリファクタリングする。replace記号でも定義するか? めんどうな、、


上記で、カーソルがどこかを選択(位置確定)すると、playRegions APIが実行される。


範囲系APIの追加

SublimeText上で表示される、エラーとか明示用のRegion(ハコ)に対応するAPI。

ハコ敷設時、特定の要素をセットできる。

要素は、上記のリアクタと組み合わせる形で発生させられる。


エラー検出からRegionをセット → Regionがある行をクリック → 

リアクタ発生 → Regionに入っている要素を取り出し、リアクタ内にセットされたAPIを実行


Unity用だと、「とりあえず要素をそのまま表示する」APIを実行している。


内容変更を逐次、WebSocketで外部に送る事も可能。


結果として

こんなかんじにエラー表示が出来るようになった

pcyt.png

ここまでで、ENSIMEができることの半分くらいが出来るようになったと思う。


あとは、稼働中プログラム値のリアルタイムオーバーレイとかも可能。 WebSocketついてるから、外部連携の自由度が良い。


UnityつかいつつScalaでの全力に向けて遊ぶ。



TODO

API一覧書く



wrote 2013/02/22 1:34:41

何しようとしてたか思い出すのを支える技術


概要

飯喰ったせいで、さっきまで書いてたコードを忘れました。

でも大丈夫! 俺にはこれがある!! みたいなものを列挙。 助かる順。



 *o ゚ |+|   。*゚  +゚ } o  |*  o。!    |!

 o○+ | ∨    | {r|! *l:     + |!*l::j o ○。

・+     ,-i| o.+  ___  。*゚}‐ 、゚ + |

゚ |i   | {r|! *l:  /_ノ ' ヽ_\   ノヾ}  |

o。!    |! * .゚ /()::::::()\  レ ノ  ゚|

  。*゚  l ・ / /// (__人__) ///\o  ゚。・ ゚  

 *o゚ |   |     |r┬-|      |   *|

。 | ・   o ゚ l\     ` ー'´    /*゚・+゚ ||    

 |o   |・゚ ,.‐- .ハ       イ | * ゚   |

* ゚  l| /    、` ニ ´ ノ  ノ   o.+ | ・    

 |l + ゚o i     ` -、{! /_   \  ○・ |o゚

 o○ |  | ヽ.     ヾ´    ̄  `ヽ  *。 

↑↑↑↑助かるっすわー↑↑↑↑



1位.テストレポート見る

「は?まずコレ見るのが常識だろ起きろ」

「ウィッス」



2位.テストを走らせる

一番速さと正確さがでる記憶よみがえり薬



3位.UNDO

とりあえずエディタの⌘+z押して考える。


4位.実行したらエラーが出るバリケード

「飯行きます?」

「アッハイ」

qあwせdrftgyふじこlp


→実行したらエラー

→正気に返る



5位.タイムアサート

忘れておけるしかけでもある。

こんなのとか。

https://gist.github.com/sassembla/4564980

他人が踏まない仕掛けは必要。他のも全部そうだけど。



6位.commit log

だいぶ焦ってくるとここ。



7位.最近開いたファイル リスト

こないだコレでマジ救われた。

→2年前に作ったエクセルどこいったか判んないけど

→2年ぶりのWindowsが覚えてた。



番外.メモとか付箋

そもメモることができるなら忘れないが一命をとりとめる事も。



手遅れ.チャット

「俺何してたっけ」

「病院行ってください。脳の。」




GAME OVER


だめだったよママン。。

wrote 2013/02/17 15:51:33

pyhackでSublimeSocketのUnity用フィルタ書いた


概要

pyhack

http://connpass.com/event/1729/

に参加して、俺俺SublimeText(ST)プラグイン SublimeSocket(SS)について、

STへと送り込むログへのフックをプログラマブルにしたくて、機構を改修した。


ついでにUnity適応用のフィルタを書いた。



ムービー

とった。

UnityのファイルをSTで開いて、エラー行が表示されるまで。

http://www.youtube.com/watch?v=OQHSPJDNDug


(0:18)

STが落ちたみたいに見える瞬間があるけど、Unityが.csファイルの監視をちゃんとやってくれないタイミングがあって、

開き直すとファイル監視がオンになり、保存時にコンパイルが走るようになる。Unityの監視が妙? それともSTがキャッシュを開いているか。


(0:45)

SSプラグインのフォルダの中に、tool/nodeTailSocket/node node_tailsocket.jsがあり、それを起動している。


(1:25)

途中、エラーにも関わらず表示が変わらないように見えるのは、クラス定義の時点でエラー出ててUnityがコンパイルあきらめてるため。



改修点

下の図の、nodeの部分にあった直書きしちゃってる問題点(過去記事参照)を解決して、プログラマブルにした。

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Document_2013-01-17_16-01-55.png

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------



以前は、nodeのtailの中に、直にUnityからのログを解釈してSublimeのAPIを叩く機構」が書き込まれていて、

例えば他の物(TypeScriptとかScalaとか)に使ったりとかする時にしんどかった。


機構としては、


Unityがなんかエラーログ吐く → nodeがそれをtail → wsでSTへ発射 → SSがそれを受ける → 解析 → STのビューへと反映 → 編集 →...


というのができれば良かったので、量や負荷なんてたがが知れてるし、node側からは全部送って、SS側で内容を振り分ける、という風にした。

ただし、今後、複数プロセスからSSに対しての内容を受ける、という予定があるので、

node側から送り込むとき、ifとか判別はないけどプロトコルは特定の物を使う、という形にした。



USAGE

まだ複雑な、複数の行程になってしまっている。今後楽にする。 nodeの起動とかはやめられる筈。


・Unity起動

・Unityからファイルを開く際のエディタ設定をSTにしておく

・STでファイルを開いたら、SublimeSocket起動

・nodetail+socket起動、フィルタ適応


あとはファイルを編集すると、Unityのコンパイルが走って、ST上にエラーが表示される。



SublimeTextに、SublimeSocketのインストール

下記から。

3系出てからpackageControlに登録しようと思う。

https://github.com/sassembla/SublimeSocket/tree/unity


実際のコードとしくみ

大きく分けて、

0.SSの起動

1.nodeを起動、SSへのフィルタの定義

2.nodeからのログの流し込み


の3工程になっている。



0.SSの起動

省略。



1.nodeを起動、SSへのフィルタ定義のセット

あらかじめフィルタをセットしておく or nodeからフィルタをセットされる必要がある。

今回は、WebSocket開通時にnode側からフィルタを送っている。 以下がUnity用フィルタの全文。


ws.on('open', function() {

console.log("OPENED");

var json = 

    {

        "name": "unity",

        "patterns": [

            {

                "[(]([0-9].*?),.*:(.*)": {

                    "runnable": {

                        "showLine": {

                            "line": "groups[1]",

                            "message": "groups[2]"

                        }

                    }

                }

            },

            {

                "Compilation failed:(.*)": {

                    "runnable": {

                        "showStatusMessage": {

                            "message":"groups[0]"

                        }

                    }

                }

            },

            {

                "(^Mono: successfully reloaded assembly)": {

                    "runnable": {

                        "showStatusMessage": {

                            "message":"groups[0]"

                        }

                    }

                }

            }

        ]

    };


ws.send("ss@defineFilter:"+JSON.stringify(json));

});

これで、

unityというフィルタ名で、正規表現と、そのパラメータを使って動く関連性を、SS上に定義できる。

上記は正規表現のマッチがあるとき、showLine関数とかを実行する。



たとえば

Assets/NewBehaviourScript.cs(6,12): error CS8025: Parsing error

みたいな文字列が送り込まれてきたとき、

正規表現からパラメータを受け取り、置換したパラメータを使う事が出来る。

上の例でいうと、パターン通過後、SS内で実行されるのは、

ss@showLine: 

{

    "line": "6",

    "message": "Parsing error"

}

になる。今はまだMessageどこにも出ないんだけどさ。



2.nodeからのログの流し込み

フィルタ名とソースがJSONで渡せればOK。

こんな感じ。


ss@detectView+filtering: 

{

    "name": "unity",

    "source": "Assets/NewBehaviourScript.cs(6,12): error CS8025: Parsing error"

}


これで、unityという名前で登録してあったフィルタに対して、

sourceが送られ、

対象のviewがどれなのかセットされ(該当が無い場合は直前のものが流用される)

そのビューの指定行に指定コメントを出す、というのが可能になる。


ちなみにエラーとかの対象のビューがSTに展開されてない場合とかは特に考えてない。

StatusBarか、このファイルがヤベーとかSideBarやDialog出せば良いのでは。


そういうAPIはないけど、STのAPIが任意に実行できるEvalは積んであるので、やろうと思ったら出来る筈。


もし~だったら、とか、そのへんのifはどうするかなー。まだ困ってないからいいや。


フィルタは、備え付けのPreferenceからファイルを使ってフィルタなど一式をまとめて定義する事も出来る。

APIマップ作ろう。



使っててだんだんST本来の設計の良さが目立つようになってきたけど、

フィルタを入力可能にしたことで、エディタ連携が凄く楽になった。


イテレーションというかラウンドトリップ(って言っていいのかこれ)が整った感じ。



次はマウスオーバーでの注釈とか、リフレッシュ、候補のぶち込みを考える。



wrote 2013/02/17 14:25:33

Unity iOSでのWebSocket


概要

UnityからiOSでのWebSocket用に、使って遊んでみる。

https://github.com/square/SocketRocket


よく見たらSquareだった。あの決済のアレですかね。



HOW TO USE(つかいかた)

悩むところ無かった。


ステップ数的に、

1.DLしてプロジェクトに該当ライブラリ部分を放り込む

2.frameworkを追加

3.ARC設定を調整(必要であれば)

4.Delegateとかをセット

でOK。



DLしてプロジェクトに該当ライブラリ部分を放り込む

下記フォルダをそのままプロジェクトに放り込めばいい感じ。


frameworkを追加

libicucore.dylib

Security.framework

を追加。



ARCを調整

SRWebocket.mに

#if !__has_feature(objc_arc) 

#error SocketRocket muust be compiled with ARC enabled

#endif


があり、ARC無いとこで動かすなカスが!! 的な様相。ちなみにtypoがry


ファイル単体に、 -fobjc-arc を追加して通過。



Delegate

socketを使用するクラスに対して、

<SRWebSocketDelegate>


と、下記メソッドを追加

- (void)webSocketDidOpen:(SRWebSocket *)webSocket{}


- (void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error{}


- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message{}


- (void)webSocket:(SRWebSocket *)webSocket didCloseWithCode:(NSInteger)code reason:(NSString *)reason wasClean:(BOOL)wasClean{}


コード

単純に、 デリゲートをセットして使えばOK。

_webSocket.delegate = nil;

    [_webSocket close];

    

    _webSocket = [[SRWebSocket alloc] initWithURLRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"ws://localhost:9000/chat"]]];

    _webSocket.delegate = self;

    

    self.title = @"Opening Connection...";

    [_webSocket open];


以上。





wrote 2013/02/13 16:47:24

msgpackハッカソンでSublimeSocketにmp用の受け口を作った

のと、Unity-SublimeText間の連携でそれを使用した話


概要

「AkkaのActor関連でmsgpackを扱ったコードを書く」と言ったな、、あれは嘘だ。


MessagePackオンラインハッカソン #1

http://www.zusaar.com/event/505055

に参加しました。


1.Obj-Cのメッセージングしてるツールのサーバ間での通信をMsgPackに変える

2.自社で使ってるAkka Actorでの通信モジュールに、MsgPackを使う

3.SublimeTextのプラグインSublimeSocket(SS)に、MsgPackでの受け入れクチを付ける


の、中から、3.SublimeSocketを選択。


理由は、一番がんばらずに動く物をまるっと公開できるから、、 あと、ちょうど、Unity-ST間の連携用のコードを書くきっかけが欲しかったので。


目標:

msgpack対応でバッファデータとかをUnity > node tail > SSで受け取り > SublimeTextに表示

特に表示する内容=データソースを、Unityのエラー、とした。



完成図

こんなかんじになった。msgpack'd dataあたりが今回作った部分。

Document_2013-01-17_16-01-55.png



以下制作過程



In&Out

サンプルとして、nodeで適当なファイルをtail、その結果をSublimeTextのコンソールへと出す、というのをやってみる。

node > WebSocket > SublimeText

が、

node > (msgpack pack) WebSocket (msgpack unpack) > SublimeText

になる筈。



各環境でのmsgpack

node側から入ったデータが、Python側に出てくる、というだけ。

そもMsgPackの受け側作った事無いので、どうした物かな的なところ体当たり。



msgpack node側

installから。

https://github.com/pgriess/node-msgpack


node wsでのbinary送信で嵌ってた。

nodeのwsのオプションでの明示に切り替え。他に、デフォだと入ってないOriginとかもそこで付けられた。

ChromeとかだとOrigin=nullでも送ってきたりするので、デフォルトでもOrigin=nullとかで送ってもらった方が良いのかな、、


msgpack  Python側

こちらもinstallから。

https://github.com/msgpack/msgpack-python


easy_install msgpack-python


なのですが、今回はST2の環境(Python2.6)で動かしたいので、

easy_install-2.6 msgpack-python


早くST3こねーかなー。3.3全力で使いたい。



成果物

UnityのエラーをSublimeText上に表示できるようになった。

msgpackは、Unityから出力されたLog用のDataを固めるために使っている。

SublimeSocket


の、msgpack branch。

https://github.com/sassembla/SublimeSocket/tree/msgpack

説明が最高にアレなのでムビとった。

http://www.youtube.com/watch?v=JSdpa_LXa8c&feature=youtu.be



内容

太字3,4が今回のハッカソンで作った部分


1. Unityを起動 > STでファイル開く > SublimeSocket起動 > 

2. node tail起動 >

3. Unityのビルド結果ログからパターン出して、msgpackで固めてWebSocketでSublimeSocketに送信 >

4. SublimeSocket側で受け取り、unpack、API Parse > 

5. STで表示される


実際にはnode tail

https://gist.github.com/4692531

の部分に、Unityのエラーログを見て、SublimeSocketの表示APIを叩くところまでが書いてある。



実際のnode tailコードはこのへん

https://github.com/sassembla/SublimeSocket/blob/msgpack/tool/nodeTailSocket/node_tailsocket.js


死にたくなるくらい汚い書きかたしてある。

この辺の書き方をどうすれば良いか、っていうのも、考えるべき事の一つ。


ここでSTへのsendの流量をしぼらず、全開素通りにして、SublimeSocket側でAPIに割り当てるとかも考えたけど、

まだプラグイン側の構造が全然二次的にプラガブルでないんで、ちょっとこう、、node側で絞って投げる形にした。

SublimeSocketにはAPIが仮設してあって、 command : JSONDATA という形でデータを与えると、エラー表示とか値表示とかが

リモートから入力できるようにしてある。

その辺のデータを、nodeから直に入力。


line28

eval:[\"sublime.message_dialog('"+data+"')\

とかで、data文字列をSublimeText側にダイアログとして表示できる。


今回は実はDialogはバグって動いてない。(STへのデータ全体の投入が0.1秒以内同時になっちゃって、STが怒った。)

line42

"eval:[\"self.setLineFromTo("+dataArray[3]+",lines)\",\"regions.append(active_view.line(lines[0]))\",\"active_view.add_regions('hereComes', regions, 'comment', 'dot', sublime.DRAW_OUTLINED)\"]";

は、メソッド名を渡してST側でevalして順に実行してる。


エスケープシーケンスェ、、、痛々しい。

JSONなのでその辺の組み立て機構を作れば良いのだと思う。

で、シリアライズするだけ。


lines配列にdataArray[3]を渡して、 > len(dataArray) = 1, 中身はST内の行番号

次の命令でlines[0]を使ってハイライト領域をSTに登録、

最後に表示をonにしている。


感想

msgpack Python 楽しいですねこれ、、、らくだし、、


Pythonで使うときに、自分が作ってる物がSublimeTextのプラグインなので、

どうやってeasy-install促すかなーとか考えが全く及んでなかった事があって、こう、アレでした。

考えさせられた。もっと考えんと。


フィルタの実例その1が作れたので、あとはUnityのエラーログの解析を、どうやって


あとnodeのwsの使い方思いっきり間違えた。Readme読めと。。



おまけで、nodeでのtail&WebSocketツールが思ったよりも使いやすいので、

自前で適当にWebSocketと繋ぐファイル監視はこのへんをデフォルトにしようかなと思ったり。

ws、tail、msgpack モジュールに依存。



ツッコミ等あれば、@toru_inoueまで。

wrote 2013/02/02 1:02:19

Unityを自動的にビルドする設定にしたときのメモ


概要

自前のプラグインというかAssetStoreで売るんだぜ的ツールのテストがしたいんだぜ。


iOS向けアプリケーションのビルドなので、 環境は必然的にMac


Unity.app内のshell

/Applications/Unity/Unity.app/Contents/MacOS/Unity

に対して、特定のコマンドを実行することで、バッチの実行が出来る。

あっちなみに Unity Pro 限定です。



チャレンジしたこと

JenkinsでUnityのiOSビルド出力を行う

DeviceとSimulator両方出す



成果物:デバイスとシミュレータのビルドを連続で行うサンプル

https://gist.github.com/sassembla/5194684



参考死霊

本当に情報が少ないんですけど、、!!


コマンドラインでのUnityの起動に関する日本語情報

http://docs-jp.unity3d.com/Documentation/Manual/CommandLineArguments.html

BuildPipeline Ref

http://docs.unity3d.com/Documentation/ScriptReference/BuildPipeline.html


先駆者:アメーバのひと

http://ameblo.jp/principia-ca/entry-11010391965.html


バッチとは

Unityのビルドスクリプトのこと。Unityのプロジェクト中に特定の形式の.csとかを含んでおく事で、Unityの動作を実行できる。



下準備

Assets/どこか/Editor フォルダをつくり、その中にビルド内容を記述した.csファイルを置く。


コマンドラインから起動する予定のコード 

BuildBatch.cs

using UnityEngine;

using UnityEditor;


using System.Collections;

public class BuildBatch : MonoBehaviour {


// build iOS app

private static void BuildiOS(){

Debug.Log("/////////// hello build ///////////");

}

}




コマンド

/Applications/Unity/Unity.app/Contents/MacOS/Unity -batchmode -quit -projectPath /Users/sassembla/Desktop/SampleProject -executeMethod BuildBatch.BuildiOS -logFile ~/build.log; cat ~/build.log


-projectPathでプロジェクト指定が可能

Assetsが入っているフォルダ までのパスでOK。


-quit で、ビルド後に「何もする事が無かったらUnityインスタンスを終了させる」ことが可能

Macだと、複数のUnityインスタンスを立ち上げられない(open -n Unity.appとかやっても怒られる)ので、必須オプション。


-executeMethodで、

クラス BuildBatch に書かれた内容が実行される。(-executeMethod BuildBatch.Build)

特に、BuildBatch クラス中のBuildメソッドが実行されます。(-executeMethod BuildBatch.Build)


☆ドキュメント読んでもやってみるまでわからんこと☆


こんなの、あんまり書く人居ないと思うので、死亡録として書いておく。


Macだと、Unityのインスタンスを複数立ち上げる事は出来ない。 open -n Unity.appとかやっても怒られる2。

ダイアログが出て怒られる。


・複数のUnity、一つのUnityから、一つのプロジェクトを同時に開くことは出来ない

たとえばエディタでプロジェクトAを開いている時、batchmodeでプロジェクトAのbatchを叩こうとすると、怒られる

ドキュメントだと、「バッチモードでプロジェクトを開くときにエディタも同じプロジェクトを開くことはサポートされていないことに留意してください」とあり、

http://docs-jp.unity3d.com/Documentation/Manual/CommandLineArguments.html


出来るプラットフォームもあるという残念な事象。

Windowsだと複数のUnity.exeが起動できる。 Linuxはわかんないや。


でもWindowsとかじゃiOS用のビルドできないし、、

まあはい。



ここまでで、BuildBatch.csを起動可能。とりあえずバッチ実行できるようになった。


で、ここからが、「ちゃんと望むモノがビルドできるようになる」までの戦いだった。


UnityでiOS向けのビルドを、デバイス/シミュレータともに行う、っつー部分の死霊がまあナイナイ。


特に、Device向けとSimulator向けをどう切り替えたもんか、まとまっている死霊が見当たらなかった。

で、結局判ったので下記に纏める。



完成版についてのGUIとの対応表

gistのコード(同上)に注釈いれつつ備忘録。


最終的に下記のようになった。

using UnityEngine;

using UnityEditor;


using System.Collections;

public class BuildBatch : MonoBehaviour {


// build iOS app

private static void BuildiOS(){

Debug.Log("/////////// build start ///////////");


string [] scene = {

"Assets/SampleAsset.unity"

};

.unityシーンを配列で渡す。UnityのGUIでの下記に対応。 なんか検出機構作って自動化すると良いと思う。

sa.pngfig.A




string dstDevice = "Device";

string dstSimulator = "Simulator";

出力先のフォルダ名を、今回は適当だけど設置した。


BuildOptions opt = BuildOptions.SymlinkLibraries | 

BuildOptions.Development | 

BuildOptions.ConnectWithProfiler | 

BuildOptions.AllowDebugging;

built playerで実行する時に使用される設定。


// set cheched

EditorUserBuildSettings.symlinkLibraries = true;

EditorUserBuildSettings.development = true;

下記のGUIに対応。デバッグとかのチェック、入れ忘れて辛い目に、、というのから、自動化で解放される。

スクリーンショット 2013-03-19 17.55.52.pngfig.B



//set Build-target : Device

PlayerSettings.iOS.sdkVersion = iOSSdkVersion.DeviceSDK;

プラットフォーム Device or Simulator のセットを行う。 エディターの次のGUIに対応。

スクリーンショット 2013-03-19 18.34.59.pngfig.C


個人的に、超驚きのポイントだった。

iOSSdkVersion.DeviceSDKっていうパラメータは確認できてたので、てっきりどこかのsetメソッドの引数で渡すものだとばかり、、、

ここもプロパティだった。 思い込みよくない。


//BUILD for device

string errorMsg_Device = BuildPipeline.BuildPlayer(scene, dstDevice, BuildTarget.iPhone, opt);

fig.B のBuildボタンを押したときに行われてる内容

押す > 吐き出し先選択 > OKを選択

の内容をひとつのメソッドに固めてある。 



if (string.IsNullOrEmpty(errorMsg_Device)){

Debug.Log("/////////// device build succeeded ///////////");

} else {

Debug.Log("/////////// device build failure ///////////");

Debug.LogError(errorMsg_Device);

}

エラーチェック(チェックするだけでSimulatorビルドには進んでほしいのでexitは無し。)



//set Build-target : Simulator

PlayerSettings.iOS.sdkVersion = iOSSdkVersion.SimulatorSDK;

// BUILD for simulator

string errorMsg_Simulator = BuildPipeline.BuildPlayer(scene, dstSimulator, BuildTarget.iPhone, opt);

if (string.IsNullOrEmpty(errorMsg_Simulator)){

Debug.Log("/////////// simulator build succeeded ///////////");

} else {

Debug.Log("/////////// simulator build failure ///////////");

Debug.LogError(errorMsg_Simulator);

}

同Simulator。

}

}



ビルド完了時

無事にDevice、Simulatorフォルダが出現。起動も出来た。ヒャッハー!

スクリーンショット 2013-03-19 18.33.57.png



注意すべき点

プロパティでなんとかしてる箇所が多いので、順番的に書かざるを得ない、


複数のプラットフォームのものを同時に並列にビルドとかはUnityの制約的に無理。

つまり、Unity.app本体のシングルトン性で保護されて動いている機構だということを忘れてはいけない。


まとめ

Unityよくできてんな。





wrote 2013/01/31 17:47:32

Sublime + WebSocketServer = SublimeSocket


概要

SublimeText2の話。


SublimeServerとかもある事だし、Sublime上でWebSocketのサーバとか動いたら、

入力が簡単で疎結合でプラガブルなエディタ補助機構がつくれるんじゃね?という内容を、

Scala全然関係ないGroovy勉強会で思いつくなどしていた。


WebSocketを使えば、外部からPushで

・エラー

・コードの挙動に対する注意点

・部分的なコンソールの結果

等をST2に送りつけてバッファに表示することが可能なのではないだろうか?

というアイデアを得て、やってみてる。



今までとこれから

よくST2でScalaとかを書いているのですが、もしWebSocketがST2に積めると、


ST2 + ENSIME Server → 補完、コンパイル補助をST2に反映


だったのが、


ST2 - websocket - コンパイラとか

という感じになる。sbtとか繋いで、バカみたいにパワーあるマシンでコンパイルして、

その間ST2には全く負荷がかからない。


しかも、テストとか動作時のパラメータを拾ってきて、テストケースの特定の値の上に表示、

なんてことも出来ちゃう。



解決したい事

ENSIMEは、ENSIME自身が重くなる瞬間、ST2も重くなる、という弱点があった。

注釈も、型について、とかは出せなかったし。


果たすべき目的は、重量級機能の外部化と、注釈機能の強化。

拡張が容易な形とかだと、うれしいな!


ということで、作っている。

https://github.com/sassembla/SublimeSocket

興味ある人いらっしゃれば、ぜひ @toru_inoue まで。

wrote 2013/01/28 5:43:34

PythonでWebsocketなサーバ


概要

ST2との連携でちょっと必要になったので作ってみる。

libevent と、geventが必要。→ 結局ST2上で動かないので、地味に書き直し!

環境はMac OSX 10.8.2 、Python 2.7

ST2でのPython環境は Python 2.6



用件

ST2への、他プロセスからの入力を行う方式として、WebSocketでのpushを試してみた。


ST2のプラグインとしてWebSocketのサーバを起動し、他のプロセスからの入力を受ける。

WebSocketのクライアントとサーバどっち書こう、と迷って、サーバにした。

他プロセス側でサーバ書くのだるいと思ったので。



使用ライブラリ一覧

libevent

結局使わない!!!

http://libevent.org

brewから入れると楽。


sudo chown sassembla:wheel /usr/local/lib

sudo chown sassembla:wheel /usr/local/include

が必要だった。


Macでこの辺がwheelになってるのなんでだろう。


gevent

結局使わない!!!

libeventに依存しているので、libeventを先に入れておくこと。

Macだとデフォルトでeasy_installが入っているので、入れるのは楽。

sudo easy_install-2.6 gevent-websocket

2.6なのは、ST2のMac版のデフォルトのPythonがv2.6だから。

Macには標準で2.7入ってるんだけどなっ なっ、、


最初、なにも考えずeasy_installしてたら、2.7が入ってて、ST2から呼べずに死んでた。

下記を参考にimport弄る or 2.6を使う、で、2.6を使う事を選択。

http://d.hatena.ne.jp/holiru/20101223/1293118186



ST2のプラグインとして、上で紹介したWS受ける機構をMainThread以外のとこで実行することで、WSのサーバは完成。

、、したと思ったんだけど、


このライブラリをST2から別スレッドで呼ぼうとしたところ、

「multiThreadには対応してねーよksg」と言われてしまうなどしていた。

http://stackoverflow.com/questions/9692089/why-gevent-on-a-flask-app-with-apache-mod-wsgi-is-raising-notimplementederror



書く

既存のヤツはだめだ!! 

(というかMainThread以外でサーバ動かそうという理屈がそもそもおかしい)


自分で書くことにした。


さまよって、Pythonのみで書かれた力作を発見。

https://github.com/kcuzner/python-websocket-server


いろいろ勉強させてもらいつつ、写経。

単体で動かす事が出来た!! 依存がないぞ素晴らしい。

https://github.com/sassembla/SublimeSocket



ST2で、ErrorとかをPushで受けて、エラー情報や値内容をバッファに表示する

続く

wrote 2013/01/20 22:42:09

ポスタブル充電池


概要

充電池に関する生活をちょっと弄って、既存の自分が抱えている問題を消し去りたい。


電池を取得

> 使う

> 使い切ったらポストに投函

> 後日別インスタンスが送られてくる or コンビ二、電気屋で貸与


こんなサービス無いかな。


月額2000くらいだったら使ってみたい。MBA充電できるクラスのやつが扱いたい。


日本だとそもそも宛先書いてあってもポストを電池を放り込んだらアウト、なんだけど。

、、、どこの国でもそうか?



動機

ノート用のバッテリー(あれだ、HyperJuiceとか)を持ち歩くのと、

家で充電してまた積むのが苦痛 (=既存の所有ルール) なので、


・好きな時に鞄にぶち込めて

・使い切ったら即パージ

・再取得もオートマチック(郵送)か、生活導線の中で自然に取得できる

だと、ものすごくうれしくて。


ちなみに、郵送のコストもさることながら、運搬パッケージのゴミも嫌いなので、生活導線上での再取得が望ましい。



メリット

どこでも作業できる力がめっちゃ高まる。

必要なときに電池を買って、使い終わったらポイできると、バッテリーを既存の所有ルールから解放される。



試してみようと思う事

現在の会社のビジネスとは完全に別路線なので、まずは勝手に試す。


解決したい問題:

・バッテリーの所持、持ち運び、充電をしたくないが、現状せざるを得ない

・使い終わったらその場でdisposeしたいが、できない(高い)


求める結果:

new battery service = current + disposability + no-retainability


wrote 2013/01/20 14:30:40

AkkaのActorでBroadcast


概要

AkkaのActorは、ScalaのActorsと異なり、ActorSystemという根幹システムを持っている。


これによって、Actor間を跨いだコントロールや、システム同士のコントロールが可能になっている。


Actors(2.9.x以前のScalaのActor)だと、この辺が無かったので、

Broadcast = メッセージが全Actorに届く とかしたい場合、自前でobject置くとかして対処してた。


要は、機構として、Centralみたいなものが無くて、自前で実装しなきゃいけなかった、と。


その辺、1WくらいでざっとJavaから使えるようにしたのがこの辺

https://github.com/sassembla/ScalaMessengerPrototype


で、Akkaで書き直してJava?なにそれ?な感じになったものを使ってはや三ヶ月。

月日が経つのは速い。

もうActorsに関しては何もかも無かった事にしていいと思う。

で、



AkkaのActorでBroadcastな仕組みを作ってみる

例として今回のお題、複数のActor間でメッセージを解釈したい場合、


AkkaのActorでは、EventBusを使ってpub-subが実装できる。

参考:http://doc.akka.io/docs/akka/2.1-M2/scala/event-bus.html



(Akka Router のBroadcastはこれとは異なった用途に使用する)

参考:http://doc.akka.io/docs/akka/snapshot/scala/routing.html


こんな感じ。

SampleBroadcasterMain.scala

import akka.actor._


case class Message(body:String)


class SampleActor extends Actor {

  import java.util.UUID


  val myId = UUID.randomUUID.toString


  def receive = {

    case message:Message => println("I am "+myId+" /message:"+message.body)    

  }

}



object SampleBroadcasterMain {

  def main(args: Array[String]) = {


   //Genereate system

    val system = ActorSystem("namespace")


    //Create actor

    val sub1 = system.actorOf(Props[SampleActor])


    //add actor to system-subscriber's network

    system.eventStream.subscribe(sub1, classOf[Message])


    //add another one -the 2nd

    system.eventStream.subscribe(system.actorOf(Props[SampleActor]), classOf[Message])


    //and add another one -the 3rd

    system.eventStream.subscribe(system.actorOf(Props[SampleActor]), classOf[Message])


    //publish messeage from here to the all subscribers.

    system.eventStream.publish(Message("hereComes! subscrivers!!"))

  }

}



実行すると

17:06:50.341 [INFO] [org.gradle.api.internal.project.ant.AntLoggingAdapter] [ant:java] I am 77175ffd-9823-4444-96ac-7dc6e7d250e4 /message:hereComes! subscrivers!!

17:06:50.342 [INFO] [org.gradle.api.internal.project.ant.AntLoggingAdapter] [ant:java] I am 6166563a-c421-4ae4-a820-8fbdec895e2e /message:hereComes! subscrivers!!

17:06:50.343 [INFO] [org.gradle.api.internal.project.ant.AntLoggingAdapter] [ant:java] I am 88b7d855-b0fa-4706-87fd-558760876024 /message:hereComes! subscrivers!!


見事に、登録したactorすべてにMessageオブジェクトが投げられている。

らっくーーー。


eventBusは、既存の用途としてDeadLetterとかに使っている。

それを外側からも使えるように、参加可能なようにしてある、という。

なるほど的な感じ。



他にも何が楽か

Logとかが楽になっています。

たとえばLoggerみたいなものを個別に積んだり、


LoggerActorみたいなのを作ってCentralPointみたいなものを自前で作ったりしてたのですが、


Akkaになると、ActorSystemに対してのLoggingの受け皿が取り付け可能なので、あとからLogをつけたり外したりがとても容易になりました。

全体像としては、


・LogActorをActorへとmixin + log出力するコードをActorの中に書く

・systemへと



systemへとlogListenerを追加

    val logListener = system.actorOf(Props[SampleLogListener])


と、

logを入力したいActorへとtraitをmixim

class SampleActor extends Actor with ActorLogging {

  import java.util.UUID


  val myId = UUID.randomUUID.toString


  def receive = {

    case message:Message => {

      println("I am "+myId+" /message:"+message.body)

      log.info("I am "+myId+" /message:"+message.body)

    }

  }

}



で、LogListenerの本体はこんな感じ

class SampleLogListener extends Actor {

  //log

  import akka.event.Logging.InitializeLogger

  import akka.event.Logging.LoggerInitialized

  import akka.event.Logging.Error

  import akka.event.Logging.Warning

  import akka.event.Logging.Info

  import akka.event.Logging.Debug

  

  def receive = {

    case InitializeLogger(_)                        print("initilaized")

    case Error(cause, logSource, logClass, message) print("Err  " + message)

    case Warning(logSource, logClass, message)      print("War  " + message)

    case Info(logSource, logClass, message)         print("Inf  " + message)

    case Debug(logSource, logClass, message)        print("Deb  " + message)

  }

}


ってな感じなので、後付けもらくちん。


ログはこんな感じにでます。

18:25:55.925 [INFO] [org.gradle.api.internal.project.ant.AntLoggingAdapter] [ant:java] [INFO] [01/20/2013 18:25:55.845] [namespace-akka.actor.default-dispatcher-4] [akka://namespace/user/$b] I am 77175ffd-9823-4444-96ac-7dc6e7d250e4 /message:hereComes! subscrivers!!

18:25:55.926 [INFO] [org.gradle.api.internal.project.ant.AntLoggingAdapter] [ant:java] [INFO] [01/20/2013 18:25:55.849] [namespace-akka.actor.default-dispatcher-2] [akka://namespace/user/$d] I am 6166563a-c421-4ae4-a820-8fbdec895e2e /message:hereComes! subscrivers!!

18:25:55.926 [INFO] [org.gradle.api.internal.project.ant.AntLoggingAdapter] [ant:java] [INFO] [01/20/2013 18:25:55.850] [namespace-akka.actor.default-dispatcher-3] [akka://namespace/user/$c] I am 88b7d855-b0fa-4706-87fd-558760876024 /message:hereComes! subscrivers!!

ここにfluentdとかへのつなぎ込みのコードを書けば、、、

あとは、、、わかるな、、?


おまけ ActorSystemへようこそ

logの中に、akka://namespace/user/ とかが出ました。


そう、このへんは、ActorSystemの名称なんです。さっき決めたやつ。

userから先に、actorが設置されている。


Supervisorとかの話につながる、ActorSystemの全体像が、この辺に関わる感じ。

詳しくは

http://doc.akka.io/docs/akka/2.0/general/actor-systems.html



サンプルとか

サンプルは下記にupしますた。

https://github.com/sassembla/AkkaSampleBroadcaster


フォルダで、

gradlew runJar -d とかやると、稼働する筈。



wrote 2013/01/20 13:33:32

Scala2.10で統合され(る用意が出来)たAkkaのActorを使う


概要

Akka 2.1.0系のActorが、Scala2.10.0に統合された。

scala 2.10.0を落としてくると、

(下記はhomebrewで入れたCellerのなかみ)

スクリーンショット 2013-01-13 22.08.25.png

こんな感じに

akka-actors.jar と scala-actors.jar が同居しているところが見れる。



公式の方だと、Migration Guide とかもあるけど、

http://docs.scala-lang.org/overviews/core/actors-migration-guide.html


正直、以前のActorにつきっきりで無かったのなら、Migrateにつきあう必要は無さそう。



Gradleでの設定

「CIできないコードは糞だ! 手離れよくなるようにまず回転を作り出せ糞共!!」「サーイエッサー!!」

早速GradleでCIできるようにセットアップ。


が、

MavenCentralに、akka-actors.jar が、まだ無い。


http://search.maven.org/#search%7Cga%7C1%7Corg.scala-lang

、、akka-actors.jar が無い。

org.scala-lang 以外でpublishされてるのかな。

ほかのものは大体あるんだけどなー。



代わりに(いつも通り)、Akka actorの2.1.0 for Scala 2.10.0 を見つけてきて対処。

http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.typesafe.akka%22

から、

akka-actor_2.10-2.1.0.jar

を取得。



差分

Acala 2.10.0に含まれる akka-actors.jar と Akka が現在配布している akka-actor_2.10-2.1.0.jar の差分は、

無い。



build.gradle

とりあえず、最新のAkka-actorを使うコードについてのbuild.gradle は、下記みたいな感じ。

sbtでも同様。


build.gradle

apply plugin:"scala"


repositories {

mavenCentral()

}


dependencies {

scalaTools  (

[group: "org.scala-lang", name: "scala-compiler",version: "2.10.0"],

[group: "org.scala-lang", name: "scala-library",version: "2.10.0"],

)


compile (

[group: "org.scala-lang", name: "scala-library",version: "2.10.0"],


// [group: "org.scala-lang", name: "akka-actors",version: "2.10.0"],not yet applied. 01/13/13 22:27:38


[group: "com.typesafe.akka", name: "akka-actor_2.10",version: "2.1.0"],

// [group: "com.typesafe.akka", name: "akka-kernel",version: "2.1.0"],

// [group: "com.typesafe.akka", name: "akka-remote",version: "2.1.0"],

)

}

まー根本的に、CIサーバにScala入れてあるんだからそこから akka-actors.jar 使えよって話なんですけど、

できることなら、Centralから落として、CIの環境に依存しないようにしたいなっていう。


Centralには依存しまくりなんだけど。

定期的にgradle内のlibをfrozenな感じにして保存しておけばOKかなと。






wrote 2013/01/13 22:29:14

Macのアプリケーションのアイコンを変える方法


概要

ダサいアイコンMUST DIE


ダサい見た目の物に慣れる事は、目の穢れにつながります。

Keep your imagination beautiful !!


余談だけど、アプリ名 icon でググって、いままで見た事無いアイコンがいっぱいでてくる場合、

オリジナルのデザインに納得されてないけどいろんな人に愛されてる、という結果だと思う。


特にデザイナーさんも使うようなツールだと、これが山のように出てくる。



効能

ツールの使い心地が変わります。

いやマジで。テンション上がるから。

自分はSublimeText2とかEclipseとかIntelliJのアイコンを変えてます。



使うもの

①こんなアイコンだったらいいのにな画像(各自がんばって探してください。)

ダサいアプリケーションほどいっぱいある筈です。

ダサいと思っても少ない場合、それを使っているコミュニティそのものがダサいのでしょう(暴言

②icon画像出力アプリ

iConify

https://itunes.apple.com/jp/app/iconify/id416289784?mt=12


が、無料でなにげにPSDとか開けて便利です。

本来はiOSApp用の画像を出力するソフトですが、Macのアプリ用にも十分使えます。

③プレビュー

icnsファイルを開く事が出来て、保存も出来る素敵なプリインされてるツール。

難はあるがぶっちゃけカットとペーストしか使いません。


手順

1.画像探し

ここでは、サンプルとして、かっこいいかんじのClojureのアイコンをWebから持ってきました。

512px-Clojure-glyph.svg.png


解像度高いやつとか、svgの素材を探す/作るといい感じです。

2.素材作り

iConifyを起動、素材画像を放り込んで、右下の iConify Folder と書かれたボタンを押します

スクリーンショット 2013-01-12 21.22.16.png

フォルダが開いて、中にはいろんなサイズの画像が出来てる筈。

スクリーンショット 2013-01-12 21.23.17.png

3.アイコン変えたいアプリのアイコンファイルを開く

今度は、アイコンを変えたいアプリケーションに対して、

スクリーンショット 2013-01-12 21.26.58.png 


右クリック > パッケージの内容を表示 > 

スクリーンショット 2013-01-12 21.26.47.png


Contents > Resources > アプリ名.icns みたいになってるファイルがひとつはある筈なので、それをダブルクリックするとかします。スクリーンショット 2013-01-12 21.29.11.png

プレビューで画像が開かれる筈。

スクリーンショット 2013-01-12 21.31.36.png


4.美しすぎるアイコンへ編集

開いたファイルを編集していきます。

あらかじめ.icnsファイルをデスクトップとかにコピーしておくと、平和が訪れるかもしれません。


「プレビュー」アプリの、右側の画像を一度クリックするとかして、

⌘ + a (全体選択)

から

⌘ + x (カット)

で消して、


サイズが合いそうなやつを

2のフォルダからみつけ、

それをプレビューで開いて


⌘ + a (全体選択)

から

⌘ + c (コピー)


で、アイコンがあったウインドウをクリックして、

⌘ + v (ペースト)


っていうことを繰り返します。


サイズが合っていれば、中心とかは勝手に合わせてくれます。

失敗しても

⌘ + z

消す前 からやり直せます。


結果

あのIntelliJが


~Before~

images.jpeg



~After~

スクリーンショット 2013-01-12 21.09.22.png

スクリーンショット 2013-01-12 21.00.21.png


うっわめっちゃイケメン。


wrote 2013/01/12 21:08:16

MacRubyXcode4.5.2 + MacRuby0.12 + Mac OSX  10.8.2 で動かす


概要

MacRubyを上記環境で試す



DL

ここから。

http://macruby.org



新規プロジェクトを作る

Xcode > 

その際、こんな感じになっている筈

スクリーンショット 2013-01-05 14.51.38.png



ビルドするとエラーが出る

MacRuby.hがない、と言われる。

それ以前に、MacRuby.frameworkが無いっていうエラーが出てる。



原因と対処

XcodeのVersion upに伴い、frameworkの場所が変更になっている。

のだけど、MacRubyのframeworkのインストール場所が変更されず古いままなのが問題。

MacRubyのIssueにもある

Build fails after updating Xcode to 4.3.3

https://github.com/MacRuby/MacRuby/issues/107


解消するには2つ手段があり、


MacRubyインストール後、

/Library/Frameworks に出来てるMacRuby.frameworkフォルダ一式 MacRuby.framework に対して、

スクリーンショット 2013-01-05 15.06.40.png

1.プロジェクトのBuild Settingの Framework Search paths 項目に、/Library/Frameworks を通す

このへんを参考に

http://watson1978.github.com/MacRuby-DoJo/blog/2012/03/07/intro-stopwatch/

コメント欄で議論がある。



2.Xcode内に MacRuby.frameworkを移す

MacRuby.framework を、 XcodeApp内の特定の箇所へとコピーする。


Xcode.app を右クリック→パッケージの内容を表示 から、Xcode.appの中身が見られる。

で、下記パスまですすみ、

Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.8.sdk/System/Library


そこに MacRuby.framework をぶち込むと、以降手を加えないでもOKになる。


ただし、

MacOSX10.8.sdk がパスに含まれている

&

Xcode.appの中をいじっている


ところから判るように


Xcodeのアップデート、Mac OSX のアップデートに影響される。

MacOSX10.9.sdkが来たら、どうしようとか、

Xcode.appがバージョンアップされたらどうしよう、とか。


直接ぶちこまんでも、既に含まれているパスとかにぶち込めば、OS updateからは簡単に逃げられると思う。


Xcode updateされたときにこの辺の問題で困った事が無いので、なんか「このパスに置けばupdateされても平気」とか情報があったら

@toru_inoue まで教えてもらえると助かります。



wrote 2013/01/05 14:54:54

Datomicの始め方


概要

おもしろデータベース Datomic 事始め

http://www.datomic.com


インフラストラクチャーを見ているだけでもかなり驚きと思いっきりにあふれたDatomic。

http://docs.datomic.com/architecture.html


公式サイトには「動かしながら学べる」感じのリファレンスがあるので、

http://docs.datomic.com/getting-started.html


はじめにこれをやってみよう的な。



DL

DatomicにはFree版とPro版があり、Free版は下記からDLできる。

http://downloads.datomic.com/free.html



in-memory dbを動かす

shell起動

bin/shell



in-memory dbのドメインを切る

uri = "datomic:mem://hello";



dbを作る

Peer.createDatabase(uri);



Peerっていうのは、インターフェースみたいなもの。

connectionを作成

conn = Peer.connect(uri);

<datomic.peer.LocalConnection@473fae05>

データを作成、次に追加を行う。

datom = Util.list("db/add", 

                  Peer.tempid("db.part/user"), 

                  "db/doc",

                  "hello world");


データを追加

response = conn.transact(Util.list(datom));



データベースを取得

db = conn.db();



クエリを打ってみる → cb/docプロパティの値が"hello world"なentity を取得する

Peer.q("[:find ?entity :where [?entity :db/doc \"hello world\"]]", db);

<[[17592186045417]]>


値が返ってきた。



続く

wrote 2013/01/05 13:10:24

UIStatusBarの高さについてのバッドノウハウ


概要

UIStatusBarの高さについて、奴ら(Apple)はどの瞬間にめり込むつもりなのか、探ってみた。



以下とりとめのないメモ


WindowaddSubすると、めり込む

のは、単純にbarの分の高さを計算して置かないから。

正し、多層的にVIewを置いて、その上で回転したいケース、っていうのは発生する。

NavigationControllerとかは、その辺の高さを読む訳で、

これは勝手に読んでいる。

なので、自前のViewControllerとかに置くと、高さが足された状態で出力される。



解決策は、

X・NavBarの高さを取得して予めBaseをめり込ませておく

▲・特定のViewをaddする場合、追加後にframeを特定の位置に動かす

・共通タイミングを割り出して何かする

・その一瞬だけアプリの状態を変える

・取得を遮る

・デフォルトを弄っておき、コード中で変化させる(ファイルを見てるならこれで対処できる)

スクリーンショット 2013-01-02 18.42.40.png

からの、

[[UIApplication sharedApplication] setStatusBarHidden:NO];

で、初期化タイミングを跨いだらOKだった。


タイミングより前だとどうなる?


インスタンス化前:アウト

addSubview前:アウト

addSubview後:OK

addSubviewの前に解放すると駄目だけど、後に解放するならOK、と。ふむ、、


ViewDidLoad後:アウト

ViewWillAppear後:アウト

ViewDidAppear後:OK


この隙間。

ViewDidAppear super前:OK

なので、ViewWillAppearでバーの存在をうやむやにすれば、行ける。


ViewWillAppearとViewDidAppearの間なので、ViewWillでhidden:YES、

ViewDidでhidden:NOとすると、何とかなる。


すげーーーーーー絶対のバッドノウハウだコレ。



wrote 2013/01/02 18:39:12

Clojure koansを触ってたら楽しくて初日の出になってた話


概要

あけましておめでとうございます。


koansっていうClojureのツール見つけたので、少し触ってみる

http://clojurekoans.com

ClojureでのTDDについて、実行しながら学べる感じのツール?」


って気軽な気持ちで動かしたんだけど、これがファイルの監視までしてるみたいで、


ちょっと書き換え→保存→勝手にテストRun→結果表示 

まで動いてて、素敵。



導入

クロージャニアンにはおなじみ、leinが入っているのが前提

http://leiningen.org/


koansを入れる

git clone git://github.com/functional-koans/clojure-koans.git



開始

clojure-koansフォルダへ移動して、

lein koan run

すると、いきなり怒られる。

スクリーンショット 2013-01-01 4.42.30.png

フォルダを見ると、いろいろ出来てる

スクリーンショット 2013-01-01 4.38.51.png


ファイルの中身は

スクリーンショット 2013-01-01 4.38.57.png

やってみよう!

runしっぱなしの状態で、


早速最初のエラーが出てる箇所を探して、いらない__を消して保存、、

したら、保存を検知して

スクリーンショット 2013-01-01 14.31.40.png


わーすてき。

おかげでスムーズに初日の出が見れました。


本年もよろしくお願いします~。

wrote 2013/01/01 3:53:31

UnityAppのViewの上にUIViewとかを置く


概要

Unity advent calendar 22日目です。

http://qiita.com/advent-calendar/2012/unity

iOS用に出力したUnityのパッケージを、Xcodeで作ったプロジェクトから呼ぶ(超手前味噌)

http://sassembla.github.com/Public/2012:12:04%201-29-54/2012:12:04%201-29-54.html


の発展系で、任意のUIViewをaddし、イベントをハンドルする、っつーことをしてみました。


つまり、

プラグインを全く書かずに、Obj-CでUnity上にいろいろ置いたりできるよね、っつー話です。



今回の内容は

・UnityのViewの上に安全にUIViewを置いて、いろいろ動作するか確認 


動画

1.Unityのプロジェクトつくって、UnityConnector DLしてきて、プロジェクトにUnityApp組み込んで、シミュレータで動かす直前まで

http://youtu.be/pmQjZwvxl-o


2.それをSimulatorでビルドするまで

http://youtu.be/HDlol7y6npY



見た目

まず通常のiOSアプリが起動、この時の起動スプラッシュはUnityのものなことに注目

スクリーンショット 2012-12-23 0.06.21.png

すぐにボタンが一つセットされた画面が表示。

スクリーンショット 2012-12-23 0.06.18.png

ボタンを押すと、Unityが起動(2度目のスプラッシュ)

1__#$!@%!#__スクリーンショット 2012-12-23 0.06.21.png

一定時間後に

スクリーンショット 2012-12-23 0.06.23.png

Unityの上に、NativeコードからUIViewを追加

スクリーンショット 2012-12-23 0.06.31.png

View上のボタンを押すと、ダイアログ表示

スクリーンショット 2012-12-23 0.06.34.png

このへんのコードは、下記にupしてあります。



コード

githubにupしてあります。 Unityのアプリ部分は含んでいないので、

自分でUnity用のプロジェクトを生成して、iOSUnityApp フォルダに放り込んでね!

https://github.com/sassembla/UnityConnector


解説

アプリケーション内で、どんなことをしているのか

ステップに分けて紹介。


1.タイトルを表示


2.ボタンが押されたらUnityを起動


3.Unityが起動したらUnity上にUIを置く


4.Unity上UIのボタンを押したらアラート



1.タイトルを表示

アプリケーション起動時、ボタンのあるUIを表示

ここはまあ、ただ単に表示してるだけ。


AppDelegate.h

SampleTitleViewController * sampleVCont;


AppDelegate.m

sampleVCont = [[SampleTitleViewController alloc]initSampleTitleViewControllerWithMasterName:CONNECTOR_MASTER];

[self.window addSubview:sampleVCont.view];

ボタンが押されたときのコードは、ただ単にDelegateにそのイベントをぶん投げるもの。

NSNotificationをラップした自作のメッセージングライブラリを使っている。


さらに、AppDelegate.mでは、

    m_application = application;

    m_launchOptions = [[NSDictionary alloc]init];


みたいな感じで、UIApplicationのインスタンスと

起動時オプションの辞書(こちらは適当に空)

の2つを保持している。

UIApplicationのインスタンスも、起動時オプションも、別に必ずここでとらないといけない訳じゃない。

説明しやすい感じに、起動時に保持するようにしてみただけ。


値は、今後のUnityAppの起動やコントロールに使用する。


2.ボタンが押されたらUnityを起動

自作ライブラリで、ボタンが押された際のイベントが、下記receiverメソッドに飛んでくる。

ボタンが押されると、

SAMPLE_TITLEVIEWCONT_EXEC_UNITY_ON_TAPPED

という名前のイベントがかっ飛んでくる。


コードに①、②とかの番号振っておいたので、それ見つつ解説する。


AppDelegate.m

- (void)receiver:(NSNotification * )notif {

    NSString * exec = [messenger getExecFromNotification:notif];

    NSDictionary * dict = [messenger getTagValueDictionaryFromNotification:notif];

    

    if ([exec isEqualToString:SAMPLE_TITLEVIEWCONT_EXEC_UNITY_ON_TAPPED]) {

/*

ignite Unity

*/

        [messenger call:KS_UNITYBOOTER withExec:KS_UNITYBOOTER_EXEC_INITIALIZE,

         [messenger tag:@"application" val:m_application],

         [messenger tag:@"launchOptions" val:m_launchOptions],

         nil];

/*

generate pinView(back button inside.)

*/

SamplePinViewControler * samplePinViewCont = [[SamplePinViewControler alloc]init];

/*

set pinView to Unity-window after some seconds.(this is for experimental.)

*/

[messenger callMyself:CONNECTOR_MASTER_EXEC_SET_VIEW_TO_UNITYWINDOW,

[messenger tag:@"view" val:samplePinViewCont.view],

[messenger withDelay:5.0],

nil];

    }


①Unity起動

Unityの起動クラスをラップしているKSUnityBooterのインスタンス(こちらも自作のライブラリ使用)に、

メッセージを送る。


値としてm_applicationm_launchOptionsを送付。


通信する先は、KSUnityBooter.mm。

ライブラリによって、receiverメソッドへと、イベントが届く。


KSUnityBooter.mmは、UnityAppそれ自体のmain.mmの内容を模している。

必要なimportがあり、intがある。

AppControllerクラスのインスタンスとして、 unityAppという名前のインスタンスを保持するようにしている。


KSUnityBooter.mm

#import "AppController.h"

#import "RegisterClasses.h"

#import "RegisterMonoModules.h"



static const int constsection = 0;

bool UnityParseCommandLine(int argc, char *argv[]);


AppController * unityApp;


- (void) receiver:(NSNotification * )notif {

    NSString * exec = [messenger getExecFromNotification:notif];

    NSDictionary * dict = [messenger getTagValueDictionaryFromNotification:notif];

    

    

    //unity-app wrapper with UIApplicationDelegate

    /*

     o     - (void)applicationDidFinishLaunching:(UIApplication *)application;

(中略)

     o     - (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window  NS_AVAILABLE_IOS(6_0);

     */

    

    if ([exec isEqualToString:KS_UNITYBOOTER_EXEC_INITIALIZE]) {

        NSAssert([dict valueForKey:@"application"],@"application required");

        NSAssert([dict valueForKey:@"launchOptions"], @"launchOptions required");

        

        UIApplication * application = [dict valueForKey:@"application"];

        NSDictionary * launchOptions = [dict valueForKey:@"launchOptions"];

        

        RegisterMonoModules();

        

        unityApp = [[AppController alloc]init];

        [unityApp application:application didFinishLaunchingWithOptions:launchOptions];

    }


ここで、UnityAppの中に入ってる、AppControllerクラスのインスタンスunityAppを初期化。

UnityAppそれ自体が起動したのと同じ挙動にするために、

AppDelegateから送付してきたm_applicationm_launchOptionsをパラメータに使う。


これで、Unityの起動が開始。

アプリの画面にUnityのスプラッシュが表示されるようになる。


ちなみに、非プロ版時のみ表示されるスプラッシュだけど、用意されたファイルを使わないようにすると

きちんとエラーで落ちる。

悪いことをしてはいけない。


で、UinityApp自体は点火できたので、次はUnity上にiOSのUIを置く。


②Unity上にUIを置く

ここでは、

アラートをセットしてあるボタンが置いてあるUIViewのSamplePinViewControlerをインスタンス化。

そのviewを、5.0秒後にそのインスタンスを自分自身(AppDelegate.mのインスタンス)へと送る。


3.Unityが起動したらUnity上にUIを置く

UnityAppの起動完了 = Unityのスプラッシュが消える、なのだけれど、UnityAppに手を加えないと

それが察知できない。

(書いてて気づいたけどもしかしたらNSNotificationでAccelの開始とかをハンドルすればわかるかもしれない。)


なので、だいたいで5秒たったら、起動してるものとする。

そのタイミングで、下記コードが呼ばれる。


AppDelegate.m

- (void)receiver:(NSNotification * )notif {


(中略)

if ([exec isEqualToString:CONNECTOR_MASTER_EXEC_SET_VIEW_TO_UNITYWINDOW]) {

NSLog(@"m_application %@", [m_application windows]);

NSAssert([dict valueForKey:@"view"], @"view required");

//get the view what want to append to Unity.

UIView * testView = [dict valueForKey:@"view"];

//get window array of this app

NSArray * windowArray = [m_application windows];

// for (UIWindow * window in [m_application windows]) {

// NSLog(@"[window subviews] %@", [window subviews]);

// }

//append view onto Unity-window

if (1 < [windowArray count]) {

[[windowArray objectAtIndex:1] addSubview:testView];

}

}


UnityのViewが作られたあと、Unityが稼働しているAppには、UIWindowが2つある。

旧来の、App起動時からあるUIWindowは実際の画面から引きはがされている(でもnilとかではない、、)

ここでは、2つめのUIWindowを適当に検出して、そこに先ほどのviewをaddSubviewしている。


このUnity用のWIndowは、Unityのインスタンス生成直後から存在はしてるんだけど、

いきなりaddSubviewすると、Unityの起動完了時にremoveされる。



4.Unity上UIのボタンを押したらアラート

UnityのUIWindow上に乗っけているSamplePinViewControlerは、こんな感じ。


SamplePinViewControler.m

- (IBAction)tapped:(id)sender {

UIAlertView * alertView = [[UIAlertView alloc]initWithTitle:@"active" message:@"can react UI-something" delegate:self cancelButtonTitle:@"DONE" otherButtonTitles:nil];

[alertView show];

}


xibで単純に組んでいて、ボタンが押されたら(touchUpInside) アラートを表示するだけ。



以上!

wrote 2012/12/22 21:13:54

主にLLVMを使用しています


概要

http://partake.in/events/9658f376-6ce3-4217-b392-b05d3de60021

昨日は @yusuke_kokubo さんでした。

りあじゅうばくはつしろ!



LLとかMLという語句がついてればOKだと思うので、


今回は

_人人人人人人人人人人_
> 突然のemscripten <
 ̄^Y^Y^Y^Y^Y^Y^Y^Y^ ̄


emscriptenとは

OCamlでJSやるのとかありますよね。 いいですよね!! JS書かずにすむとかGooooodです。

emscriptenは、

その辺の「こんな言語からJSが生成されるなんて!!」的な言語のお友達です。

こわくない。



Q.どこがMLだったりLLなのか


A.LLVMです。 JS生成にLLVMを使用しています。


emscriptenは、LLVMを使って、いろんな言語のコンパイル結果としてJSを吐き出します


毎回なぜかこの辺でドン引きされますが、

コワくない。


本体

githubにホストして開発されてる

https://github.com/kripken/emscripten/wiki



わかりやすい日本語での解説

Emscriptenの論文読んだ。Webの賢い選択。

http://akidev.hateblo.jp/entry/2012/04/12/233934



自分も5月くらいになんか書いてました。もう古い。

emscriptenを動かしてみる

http://sassembla.github.com/Public/12:05:21%2017-38-30/12:05:21%2017-38-30.html


補足

LLVMって?

コレ。 コンパイラみたいなものです。

http://llvm.org



やってみよう!

今回は、Objective-CのコードをJS化してみるよ!


といってもヘビー級だと絶対破滅するので、

軽めのをソースからJS化してみます。



脱線するけど。

本来の「言語をコンパイル可能な状況に持ち込む事で、出来るとうれしい事は何か」;


1.メッセージングの機構とか、JSでやるとクソみたいな事を、Cとかで書いてJSに持ち込む

2.人の手が絶対につけられないJSソースコードを吐く(マイナーチェンジや場当たりなど、変更可能性の更迭)

3.テストが容易


2.3が絶大なメリットだと思ってて、

変更可能性の無い = 人間が弄れない、なんだけど、

そういうソースコードでなにかをコントロールする世界にしていかないと、Webまわりはもうずっとこのままだと思う。


外部化のために、変更可能性をより上部に持っていく必要を感じているのです。



で、手順!


MacでClangをインストール

Xcodeから入れると、フレームワークとかのパス設定をはしょれて凄く楽です。

Xcode > Preferences > Downloads > 


最初llvm自体をDLして、ガチで挑んで死ぬかと思いました。


Windowsでも調べてみたら相ッ当なドMな方だとお見受けしますが、

何人か「環境作ってみたぜ!」な方々がいらっしゃいました。正直koeee。



Cの簡単なファイルを試しに一発ビルド

対象のファイルはこんな感じ。


test.c

#include <stdio.h>

int main()

{

    int i = 0;

for (i = 0; i < 99; i++) printf("hello, world %d ", i);

    return 0;

}


適当な回数hello, world っていうプログラムです。


ビルド

llvmは、clangというフロントエンドツールを介してコントロールします。


ビルドコマンドは

clang test.c -v

スクリーンショット 2012-12-18 22.29.04.png

成果としてa.outができましたよっと。


スクリーンショット 2012-12-18 22.29.26.png



Obj-Cの簡単なファイルを試しに一発ビルド

対象のファイルはこんな感じ


test.m

#import <Foundation/Foundation.h>


@interface X : NSObject

@end


@implementation X

-(void)hello {

       printf("Hello ");

}


@end


int main() {

X * obj = [[X alloc] init];

  [obj hello];

    return 0;

}


ビルド

clang  -fobjc-arc -framework Foundation test.m -o testObjC.out


出来上がったバイナリを実行すると、

スクリーンショット 2012-12-21 6.23.45.png





ビルドできる環境が整ったら、.ll/.bcファイルを出力

emscriptenに喰わせるため、LLVM IR(Intermediate Representation) = LLVM上でのコード中間表現 を生成する。



ちょっと脱線しつつ説明しておくと、


llvmは「ローレベルなバーチャルマシンで色んな事をする為のコンパイルの基盤」で、

その目的は

・言語をビルドする行為それ自体と、ビルドしたものが実際に動作するアーキテクチャを切り離す

・中間言語の時点で最適化を施す

というもの。超ザックリ。

で、.ll/.bcファイルは、その中間言語化された状態。optとかを使って最適化ができる。ここではやんないけど。

実行形式を引きずってない、意図だけのソース。

その辺をclangからつくる。



clang -O3 -emit-llvm test.m -c -o test.bc


こんなのが出来る。

スクリーンショット 2012-12-18 23.53.50.png



emscriptenのセットアップ

割愛。

参考になるステキな記事。

c/c++ -> javascript 変換compiler - emscripten を試す

http://d.hatena.ne.jp/end0tknr/20120714/1342233561



作成した中間言語をemsriptenでjs化

C言語版

./emscripten/emcc ソース.c

出力されるのが、.jsファイル。

-o 出力ファイル名 とかで調整も可能。



Cオリジナル

https://dl.dropbox.com/u/36583594/shared/test/test.c

js化したものをhtmlに入れたヤツ

https://dl.dropbox.com/u/36583594/shared/test/test.html

Cのprintfに対応して、プリント文が出てるぞ!! デバッガを見てね!

スクリーンショット 2012-12-19 0.34.15.png


Obj-C版

オリジナル

https://dl.dropbox.com/u/36583594/shared/test/test.m

★最新のemsだと、.llからの変換が駄目らしい!!!

調整中、、2012/12/18 23:57:43



明日は @kei10in さんです。


番外編失敗狂の詩

何手か、悪手っぽいものを試して失敗したのでメモまでに。


Obj-Cからc++とかに変換すればいいんじゃね?

clang -rewrite-objc .mファイルをcppファイルに変換できるので、それをビルドすれば、、!!という。

アイデア自体はまあ平和だったんですが、詰まったので方向転換しました。









以下メモ



emscripten側を弄る

・設定ファイルを更新

LLVM_ROOT = os.path.expanduser(os.getenv('LLVM') or '/usr/bin/')



llvm-linkとllvm-arとoptとllvm-asとllvm-disと

llvm-nmを追加



で、


./emscripten/emcc /Users/sassembla/test/ems/test.m.cpp

(Emscripten: settings file has changed, clearing cache)

warning: LLVM version appears incorrect (seeing "Apple clang version 4.1 (tags/Apple/clang-421.11.66) (based on LLVM 3.1svn)", expected "clang version 3.1")

(Emscripten: Running sanity checks)

/Users/sassembla/test/ems/test.m.cpp:69:9: warning: '__block' macro redefined

#define __block

        ^

<built-in>:20:9: note: previous definition is here

#define __block __attribute__((__blocks__(byref)))

        ^

/Users/sassembla/test/ems/test.m.cpp:73:10: fatal error: 

      'Foundation/Foundation.h' file not found

#include <Foundation/Foundation.h>

         ^

1 warning and 1 error generated.

emcc: compiler frontend failed to generate LLVM bitcode, halting


なので、

frameworkを読むように設定して、


./emscripten/emcc -framework /System/Library/Frameworks/Foundation.framework/Headers/Foundation.h /Users/sassembla/test/ems/test.m.cpp -o a.out.js


おおーエラー無く出せた。

でもこれ何が出てるんだろう。。。



CPPがそのまま吐かれてた

グハー


ということで、このルートは無し。


再度チャレンジ


./emscripten/emcc -framework  /Users/sassembla/test/ems/test.m.cpp -o a.out.js


llvmが吐き出す中間成果物をもとに、emscriptenしてみる


llvm-dis

llvm-dis /Users/sassembla/Desktop/compile/test.bc

wrote 2012/12/18 00:00:00

クリップボードの内容を保存するアプリをいろいろ試してみた


概要

⌘ + c でコピーした項目を、リスト状に保存しておけるアプリを探していた。

事の発端は、長らく使ってたClipMenuというアプリケーションの開発が停滞しているっぽくて、


ClipMenu

http://www.clipmenu.com/ja/


10.6向けリリースを最後に停止してるんだよね、、、


バグレポとか数回、半年以上前にやったんだけど音沙汰ないし、オープンでもないから改修参加も出来ないしで、

そろそろ後継探すべ、、ってことで。



何に使ってたの

コーディングとか。


ある機能Aを作る時、まずまるっと動くとこまでコード書いて、

その後、連携する先の機能Bを書いて、

その中でAに返す情報を書いて、、

とかする時に使ってた。

ようは、

記述する内容が複数のシーケンスとかファイルとか段取りとかにネストする時、それを見越して

予めコピーしとく、という。


Aに渡す予定の情報を、いちいちAに戻って確認してなにやら、っていうのが面倒だったので、

Aを書く時点でAに渡すべき情報を一旦書いてしまって⌘ + cとかしておいて、消して、


B書く過程でコピペとか移動とか色々すると思うけど


Bの中でAの情報使いたい時、Aを見に行かずに、クリップボードの履歴から掘り出して貼る、とか。


覚えておくのが面倒なことは、マシンに覚えておいてもらおうぜ的な。

(ただしパスワード、てめーは駄目だ。)



お題:

ゆるっとTwで聞いてみたけど、そもどんなものを探しているのか判りづらかったと思うし、

自分で探す + しりあいづてに聞いてみるなどした。




⌘ + c した項目が、リスト状にならぶやつ。

選択すると、現在フォーカスがあたっているアプリケーションに対して、ペーストが行える、というもの。

MacでOSX 10.8以降対応してればOK。


以下、Candidates:候補アプリ



Flycut

じぶんで見つけたもの。

オープンソースで、Github上にコードがあった。


特定キーショートカットを押している間だけ、過去にcしたものが表示されて、

左右でどれかを選んで離した瞬間ペースト、という


「おまえ、、、これ、、、」

的なUIを体験できた。スクリーンショットも取れない。。。

無し。


唯一凄いなーと思ったのが、秘匿フィールド(文字が*とかに変わるフィールド)の内容は記録しない、という点。

UI的に恐ろしく使いづらいので、コミットする気にでもならないと使わなそう。



CopyLess (Light)

教えてもらったもの1。


無料版と有償版がある。画面とかは無償版のもの。

有償版は¥600


cした内容が、リストで アイコン + 内容 として表示される。


QuickLookにも対応していて、ペーストするものがどんななのか、見れる。

Webブラウザとかで見てる途中の内容とかもコピペできるし、

性能はClipMenu(今回見限ったやつ)に非常に近い。


ClipMenuよりも便利な内容として、検索窓とかもついてて、非常に有用。⌘+fでフォーカス移る点



メニューバー上のアイコン

スクリーンショット 2012-12-17 15.09.03.png

と、メニュー

スクリーンショット 2012-12-17 15.25.07.png

Appアイコン

cpl.png

見た目

スクリーンショット 2012-12-17 15.12.41.png

上部バーを消した所。

スクリーンショット 2012-12-17 15.08.24.png


QuickLookしたとこ

スクリーンショット 2012-12-17 15.24.33.png

設定画面

できることが多すぎ + 有用。

特にすげーと思った内容をアップ。

ショートカット、けっこう細かくセット可能。Favoとかもある。

スクリーンショット 2012-12-17 15.30.10.png

表示項目をカスタマイズ可能、メニューバーからも消せる。正直メニューバーにモノが並ばない方が好きなので助かる。

Use compact とかやると、全項目が80%くらいのサイズになる。

スクリーンショット 2012-12-17 15.28.22.png



Clyppan

教えてもらいもの2。


有償版のみ。¥250

基本性能はCopyLessと全く同じ。


cした項目をfavoriteできる、というのがある。 ふぁぼ。

お好きでしょうか、ふぁぼ。


ふぁぼった項目は別途Favoriteメニューに残すことができる。

正直自分はこの機能あんま使わない。


自分が使った難点としては、PrefernceがAppのウインドウからしかアクセスできないところ。

メニューバー上のアイコンからは触れない。


何故。



メニューバー上のアイコン

スクリーンショット 2012-12-17 15.25.16.png



Appアイコン

cp.png



見た目

スクリーンショット 2012-12-17 14.59.43.png

QuickLookしたとこ

スクリーンショット 2012-12-17 15.21.23.png


設定画面

スクリーンショット 2012-12-17 15.21.32.pngスクリーンショット 2012-12-17 15.21.39.png


という事で

自分はCopyLessをつかうことにしましたとさ。




wrote 2012/12/17 14:59:47

いろふアドベントカレンダー 14日目です


概要

コアはコレです

http://atnd.org/events/34079


前日13日は @bufferings さんで、これでした。

http://bufferings.hatenablog.com/entry/2012/12/13/035334


同14日は @skrb さんで、これらしいです。

http://skrb.hatenablog.com/entry/2012/12/14/005301


15日は @kiy0taka さんで、これはスゲー、、!!

http://d.hatena.ne.jp/kiy0taka/20121215/1355568984



内容

Unityっつーゲームエンジンで作った、いろふさんのせかいにご招待します。


Welcome to ザ★イロフ★ワールドッ!! 最高に灰ってヤツだ!!



症状

十字キーで移動、スペースキーでジャンプできる気がします。


IIrofTheWorld.html


(UnityのWebプラグインをいんすとーるする必要があります)

(入ってない場合なにか言われるので入れたりしてくだしあ)



ルール

なんとなーーく察っすることがうっかり出来るのではと思いますが、

今回のいろふさんは登れます。


ゴールは目玉とさせていただいております。

よじよじして、ぜひ天空からの眺めをお楽しみください。


スクリーンショット 2012-12-14.png

wrote 2012/12/14 00:00:00

UnityiOS向けビルドを別アプリに含んで起動する


概要

最近Unityで遊んでるのだけど、ちょっと思う所あってゴニョゴニョと弄ってみてた。


今回試したのは、iOS向けにビルドしたUnityのアプリパッケージを全く弄らず

Xcodeで自前作成したアプリケーションから起動してみようぜ、というもの。

追求したい利点としては

・端末へのインストールをもうちょい楽に自動化したい

いろいろとまあ、なんだ、そのままやると大変。


iOSのネイティブアプリケーション部分のバージョン管理がしやすくなる

本命。

iOSのプロジェクト本体と、まるっと生成されるUnityでのアプリケーション、

従来ならUnityに完全包含されてしまう、iOS側の設定がとっても楽になる。


などなので、決して、非プロ版で起動スプラッシュ外そうぜとかそういうノリでやっている物ではない。

、、プロ版は、、、いいぞ、、、!!



完成系のイメージ

自分で適当に制作したアプリケーションに、任意のUnityのプロジェクト一式を読み込んで、

任意のタイミング、コード上のポイントから、Unity起動~終了、などが扱えるようになる。


手順

①UnityでiOS用にプロジェクトをビルドしておく。プロ版とか、そうでない版のプロジェクトを用意


②所変わって、XcodeでiOS用の新規プロジェクトを用意、ここではSampleProjectって名前にする

ちなみにARCは使用不可

Unityが吐き出すApplicationがバリバリにAutoreleasePoolとか使ってるので。

スクリーンショット 2012-12-04 2.13.22.png

③SampleProjectのprefixに設定を追加する 


作成したアプリケーションのXcode上でのグループ

SampleProject/Supporting Files/SampleProject-Prefix.pch 箇所に下記を足す。


#ifdef __cplusplus

extern "C" {

#endif

    void UnitySendMessage(const char* obj, const char* method, const char* msg);

#ifdef __cplusplus

}

#endif


#define printf_console printf


#define IPHONE_TRAMPOLINE 1


こいつは、Unityのアプリケーションを足した際、主にprintf_consoleの為に使う。

UnitySendMessageも大事だけど。


④下記のframeworkを追加


SystemConfiguration.framework

CoreLocation.framework

MediaPlayer.framework

UIKit.framework

OpenGLES.framework

QuartzCore.framework

OpenAL.framework

libiconv.2.dylib

CFNetwork.framework

AudioToolbox.framework

iAd.framework

CoreMedia.framework

CoreVideo.framework

AVFoundation.framework

CoreGraphics.framework

CoreMotion.framework

GameKit.framework


すべてUnityに含まれているもの。


⑤UnityをBootするクラス UnityBooter を作成する

NSObjectを拡張してクラスを一つ作る。

起動部分でC++を使うため、Obj-C++、拡張子は.mm にする。


この後で、Unityのプロジェクト一式を含むようにするため、

このクラスの初期化メソッドからUnityを起動できるようにしむける。


下記が UnityBooter.mm の内容。


#import "UnityBooter.h"


#import "AppController.h"

#import "RegisterClasses.h"

#import "RegisterMonoModules.h"


static const int constsection = 0;

bool UnityParseCommandLine(int argc, char *argv[]);



@implementation UnityBooter

- (id) initWithApp:(UIApplication * )application withLaunchOptions:(NSDictionary * )launchOptions {

    if (self = [super init]) {

        RegisterMonoModules();

        

        AppController * unityApp = [[AppController alloc]init];

        [unityApp application:application didFinishLaunchingWithOptions:launchOptions];

    }

    return self;

}

@end


この時点で、下のようなプロジェクトの構成になっているはず。

スクリーンショット 2012-12-04 2.12.43.png

で、initWithApp メソッドをAppDelegateから適切な引数で呼ぶようにする。

UnityBooter.hにも書いておこう。


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

{

    self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];

    

  UnityBooter * booter = [[UnityBooter alloc]initWithApp:application withLaunchOptions:launchOptions];

    

    self.window.backgroundColor = [UIColor whiteColor];

    [self.window makeKeyAndVisible];

    return YES;

}




⑥UnityでiOS用 Device用ビルドを、自作プロジェクトに放り込む

ほんとにそのまま放り込む。

ここでは、Unityから吐き出したiOSアプリ用プロジェクトを、iOSUnityという名前にした。

(Device用に設定したため、Deviceでしか動かないが、過去の記事を参考に何かすると、Simulatorでももちろん動かせる。)

http://sassembla.github.com/Public/2012:12:01%2012-03-18/2012:12:01%2012-03-18.html

一度SampleProject フォルダに放り込んだ後、XcodeからSampleProjectへとaddする。

スクリーンショット 2012-12-04 2.14.32.png



そのままプロジェクトに含んだ結果。

スクリーンショット 2012-12-04 2.16.32.png

⑦Unityから持ち込んだ main.mmファイルを、remove reference する

Xcodeグループ内、iOSUnityApp/Classes/main.mm の参照を消す。

mainが2つあると、そもビルドが通らないので、referenceのみでいいからremoveする必要がある。

ここだけはどうしようも無かった。 ファイルを捨てる必要は無い。

スクリーンショット 2012-12-04 2.26.17.png

⑧C++ Standard Library の設定を、Defaultに変更

スクリーンショット 2012-12-04 2.33.43.png

Compiler Default に変更する。

スクリーンショット 2012-12-04 2.33.51.png


⑨Valid Architectures を、armv7 armv7s から、armv7 のみに変更する

Unityで使用しているライブラリが、armv7sに対応してないので、armv7のみをValidなアーキテクチャとして設定する。 

(Unityは、ターゲットがarmv7s対象のみ、とか設定したら、7s対応したVersionのライブラリを吐くのかもしれない。未確認。)

スクリーンショット 2012-12-04 2.51.05.pngスクリーンショット 2012-12-04 2.56.23.png

⑨Build Active Architecuture Only に No と入力

ビルド時にarmv7のみを設定するようにしたため、この部分がNoでないと矛盾してエラーが出る。

スクリーンショット 2012-12-04 3.20.33.png

⑩Build Phases に、UnityのDataをアプリケーションビルド時に内部にコピーするスクリプトを追加する

スクリーンショット 2012-12-04 2.58.40.png

スクリーンショット 2012-12-04 2.58.46.png

位置 = 実行順序をドラッグして調整

スクリーンショット 2012-12-04 2.58.53.png

内容として、下記を入力。太字部分はUnityのプロジェクト名


rm -rf "$TARGET_BUILD_DIR/$PRODUCT_NAME.app/Data"

cp -Rf "$PROJECT_DIR/iOSUnityApp/Data" "$TARGET_BUILD_DIR/$PRODUCT_NAME.app/Data"

if [ "$PLATFORM_NAME" == "iphonesimulator" ]

then cp -f "$PROJECT_DIR/iOSUnityApp"/*.png "$TARGET_BUILD_DIR/$PRODUCT_NAME.app/"

                          fi

これで、iOSUnityApp内に含まれるDataフォルダが、アプリケーションビルド時に、.app内に含まれるようになる。

これをやらないと、Unityの起動後、シーンデータなどが読み込めずに落ちる。


おまけ①:非プロ版の場合、Applicationに自前で含まれている Supporting Files 下のスプラッシュを消す必要がある

Unityのプロジェクトに含まれているものが使われないと、落ちる。

素晴らしいフェイルセーフ。異論は無い。


アプリケーションの中の SampleProject/Supporting Files の中のpngを削除。

これで、自動的にUnityプロジェクトに含まれるものが使われる。


スクリーンショット 2012-12-04 3.15.42.png


おまけ②:実機にインストールする場合、一度Xcodeを再起動しないと、Valid Architectures の設定が読み込み直されない。

Xcode終了して再度プロジェクト開けばOK。




以上で、ビルドは通り、実機を繋げば実行できる、、ハズ。


参考までに、Unityのプロジェクトを含まない外装一式をgithubに置いておいた。

https://github.com/sassembla/UnityFreeLocation_SampleProject


起動からボタンを表示するViewをつけて、ボタンが押されたらUnity起動、という遷移のスクリーンショット

めざめたおっさんが走り出す。 時間が戻ってるのはすいません、キャプチャミスった。

非プロ版だと、ちゃんとUnity起動時に powered by Unity のSplashが出る。

スクリーンショット 2012-12-04 3.58.48.pngスクリーンショット 2012-12-04 3.58.56.png


ツッコミ等あれば、@toru_inoueまで。


wrote 2012/12/04 1:29:54

SublimeText2アドベントカレンダー2012


概要

みんなだいすきSublimeText2、のアドカレ!

http://www.adventar.org/calendars/20


3日目です。

written by @toru_inoue



SublimeText2でのプラグイン作りで、ハマりやすいところについて

つらつら3点ほど、まとめつつ書きます。


以前作り方的に悩んだ部分を纏めたのですが、

http://bit.ly/UaWF0u


身内からも、「羅列してある感じで良くワカんねぇッス!!」とか

「★になれ!! クマと戦え!!」とブワッ(´;ω;`)な感じだったため

Tipsとして転生します。



1.Sublimeの command と python ファイルの連携について

ST2には、command と呼ばれる概念なものがあります。

{"id": "Gradle", "caption": "Build current project", "command": "gbuild" }

この command を実行すると、プラグインフォルダ中の なんちゃら.py の中身が実行される訳なんですが、

実行されるメソッドは、下記のルールさえ守っていれば何でも良いみたいです。


①なんちゃら.pyが存在する

②上記で言う、gbuild を先頭に含んでいるクラス定義がある

ここが一番厄介。


gbuild はもちろんのこと、


gbuildCommand とか

gbuildHyahhar とかでもOK。


さらに、一般的にはclass大文字で始めるんじゃねェの的な意味で、

Gbuild とかもOK。

ただし、途中での大文字の扱いが歪で、


command の呼び出し定義を

"command": "gbuildDependents"

とか書いてしまって、

gbuildDependents

みたいなクラス名で定義しても、command が呼ばれません。


このへんは結構歪で、結局自分は command 定義部分はすべて小文字、

クラス定義側は頭のみ大文字、にしました。

信じてたのに!! 最初の大文字はOKだから信じてたのに!!

はい。駄目です。



③そのclassが sublime_plugin.TextCommand / sublime_plugin.WindowCommand / sublime_plugin.ApplicationCommand のどれかを継承している

微妙に用途が異なるST2プラグイン用のクラスが定義されてるので、継承します。


それぞれの用途については下記参考。

http://www.sublimetext.com/docs/api-reference#sublimeplugin.Plugin


④run メソッドが定義されている

⑤そのメソッドが継承したclass に対応する引数持ってる

ふまえると、上記のcommand gbuild  の定義はこんな感じになります。


import sublime

import sublime_plugin


class Gbuild(sublime_plugin.TextCommand):

  def run (self, edit) :

    # 何か処理



2.いつの間にかショートカットがついてる場合

コレですコレ。

スクリーンショット 2012-12-02 17.21.52.png

前出の command について、ショートカットを設定出来ます。


設定は、プラグインパッケージ内の

Default.sublime-keymap ファイルから行えます。


ただ自分がモロにハマった事象があって、把握までちょっとかかったので共有までに。


・既にショートカットが定義されている command と同じ名前の command を定義してしまうと、

Packageの壁を越えてショートカットマークが勝手に付く


例えば、buid、って名前の command を定義しちゃったとしましょう。

すると、CommandPalette とかに出る訳なんですが、


他のプラグインで build って command が既に定義してあってですね。

しかもショートカットも既に書いてあったんですね。


結果、自分が定義したcommandが表示されるべき箇所にも、ショートカットマークが出ちゃいます。

最初、何故付いたんだろう、なんだろうなーってわからんかったっすわ。


解決策としては、

・command の名前をユニークなものにする

・キーボードショートカットは無かった事にする

などです。

キーボードショートカットを簡単に定義できるのもST2のステキな所! なのですが、


ぶっちゃけCommandPaletteがあるのでもう必要ないんじゃないでしょうか。

ショートカットは簡単に他のとぶつかるし。



3.プラグインから外部プロセスを呼ぶ

いろいろな方法が有るのですが、自分は


subprocess.Popen

を使っています。


こんな感じ。


self.process = subprocess.Popen(shlex.split(self.command.encode('utf8')), stdout=subprocess.PIPE, preexec_fn=os.setsid)

引数には、shlexで文字列をArrayに分割して放り込む、という風にしています。

一応Tipsとしては2つあり、


・stroutの内容を取得するために、PIPEを設定


こうする事で、

self.process.stdout 

関連の標準出力が監視できます。


・このプロセスの処理に時間かかり過ぎたときにkillできるように、preexec_fn=os.setsid を設定


こうする事で、

os.killpg(self.process.pid, signal.SIGTERM)


が通用します。

ほんとは2.7以降ならもっと別の手法が有るっぽいのですが、ST2が使用するのはPython2.6 なので、

涙をのんでこんな所です。



おしまい

こんな所でしょうか。

明日は4日目、 sada hirai さんです。

wrote 2012/12/03 00:00:00

GradleXcodeプロジェクトをビルド/テスト


概要

Gradleのプラグインで、XcodeのiOSビルドとかを補助するものがあった。

https://github.com/openbakery/gradle-xcodePlugin


その簡単な使い方を見つつ、発展系として

TestFlightに放り込んだり、

先のUnityビルドとの連携を試してみたり、

超願望としてはCocoaPodsと連携させてみたい。


サンプルプロジェクトはgithubにあげておいた。

https://github.com/sassembla/Gradle_XcodeSample


手順と読者想定

iOSでのアプリ作りとかしたことあるような前提で書いてます。


Xcodeで新規プロジェクトを作成、UnitTestとか適当に全部のせ、みたいなところに、

Gradleでの一般的なビルドスタイルとして build.gradle ファイルをプロジェクトフォルダに置いた、という地点からのスタート。



手始めにSimulator用ビルド

プロジェクトフォルダ直下のbuild.gradleを編集。


build.gradle

buildscript {

repositories {

maven {

url('http://openbakery.org/repository/')

//url uri('/tmp/repo')

}

mavenCentral()

    }

    dependencies {

        classpath group: 'org.openbakery', name: 'xcodePlugin', version: '0.6.+'

    }

}



apply plugin: 'xcode'


buildscript {

    configurations.classpath.resolutionStrategy.cacheChangingModulesFor 0, 'seconds'

}


xcodebuild {

sdk = 'iphonesimulator'

target = 'Gradle_XcodeSample'

}


特に解説がいらないんじゃないかな的な気もするくらい、簡単なビルドスクリプト。


で、Terminalでgradle xcodebuild とか実行すると、

スクリーンショット 2012-12-31 2.00.33.png

Simulatorでのビルド、成功!。



Simulatorでのtest

前提として、下記を満たしている必要がある。


・テスト対象は、Xcodeで作ったOCTestUnitのコード

・テスト用のbundleがある


みためでいうとこんな感じ。

スクリーンショット 2012-12-31 1.24.39.png

で、OCUnitをコマンドラインから実行するために、TEST HOST のパラメータを空にする。

理由はおまけで後述

スクリーンショット 2012-12-31 1.27.26.png


で、build.gradleの設定を調整する。

xcodebuild タスクの中に1行追加

build.gradle

xcodebuild {

sdk = 'iphonesimulator'

target = 'Gradle_XcodeSample'

unitTestTarget = 'Gradle_XcodeSampleTests'

}

これで、xcodebuild実行時に、unitTestTargetで指定したターゲットに含まれるOCUnitTestが実行される。

試しに実行すると、一件のテストが失敗する。

スクリーンショット 2012-12-31 1.49.31.png

通常のGradleの動作だと、テストが成功したり失敗したりしたリストがxmlファイルとして生成されるのだけれど、

このプラグインにはまだその出力機構は無い模様。


ちなみに自作はかんたんな筈です。


Deviceでのビルド

魅力を感じないのでパス。



Deviceでのテスト

あまり魅力を感じないのでやはりパス

Xcodeつないでるとき以外やんないでしょ。



Testflightとの連携

また今度。



おまけ

なんでSimulatorでTestする際、Test Host 項目を空にするのか

Xcodeをインストールすると使える Xcodebuildコマンドで、OCUnitの実行は出来る。

んだけど、


xcodebuild -configuration Debug -sdk iphonesimulator -target Gradle_XcodeSampleTests TEST_AFTER_BUILD=YES DSTROOT=/Users/sassembla/Desktop/Gradle_XcodeSample/build/dst OBJROOT=/Users/sassembla/Desktop/Gradle_XcodeSample/build/obj SYMROOT=/Users/sassembla/Desktop/Gradle_XcodeSample/build/sym SHARED_PRECOMPS_DIR=/Users/sassembla/Desktop/Gradle_XcodeSample/build/shared


とか実行しようとすると、

/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/Tools/Tools/RunPlatformUnitTests:81: 

warning: Skipping tests; the iPhoneSimulator platform does not currently support application-hosted tests (TEST_HOST set).


って言われて、テストがスキップされてしまう。

ようは、SimulatorでTestする場合、TEST_HOSTのパラメータに何かセットしてあると、サポートしてないんでスキップするぜ、っていうことだった。

デフォルトで、このパラメータはプロジェクト自体のパスが入っている。


で、上でやったように、このTEST_HOST項目を空にすることでテストがスキップされずにちゃんと実行されるよ、ということ。


wrote 2012/12/01 22:35:14

UnityのDeviceビルドをSimulatorビルドに換装する


概要

適宜Simulator版とDevice版を動かし分けたい。

具体的に言うと、

・Simu版をサーバで動かしてCI

・そこからDevice版を実機転送で動かして遠隔実機CI


などがしたい。


ので、片方からもう一方が作れないか試してみた。

特にDevice版からSimulator版、その後またDeviceに戻す、というのをやってみた感じ。



差異

DeviceビルドとSImulatorビルドの差異は、下記のフォルダにのみある。


Libraries/

Assembly-CSharp-firstpass.dll.s

Assembly-CSharp.dll.s

Assembly-UnityScript-firstpass.dll.s

Assembly-UnityScript.dll.s

mscorlib.dll.s



Data/Managed/

Assembly-CSharp-firstpass.dll.mdb

Assembly-CSharp.dll.mdb

Assembly-UnityScript-firstpass.dll.mdb

Assembly-UnityScript.dll.mdb


PROJECT.xcodeproj/

project.pbxproj

ここの特定の設定項目を変える必要がある。(ビルド自体にも影響)



Libraries/以下

フォルダごと入れ替える事で解決できる。



Data/Managed/以下

フォルダごと入れ替えることで解決。

実はアプリが起動するまで全く触られないらしく、無くても動く。


無い場合は起動後に落ちる。

その際のエラーは

Failed to load AOT module 'Assembly-CSharp-firstpass' while running in aot-only mode.



PROJECT.xcodeproj/の内容変更

を変更する前に、タブでDevice/Simulatorとかが選べるようにする。

プロジェクトアイコン > Build Settings >

SupporterPlatform で、iOSを選択。

スクリーンショット 2012-12-01 18.38.37.png


スクリーンショット 2012-12-01 18.38.42.png

独自に文字書いてあるのを変更。

Scheme から、Simulatorが選べるようになるはず。

スクリーンショット 2012-12-01 18.41.01.png

加えて、一番大事な、


OTHER_CFLAGS = -mno-thumb


を、


OTHER_CFLAGS = -DTARGET_IPHONE_SIMULATOR=1


に変える。



(SimulatorをDeviceにするのではなく、

Deviceを一度Simulator化したものを再度Device化する話。)


LibraryとDataを変更、

OTHER_CFLAGS = -DTARGET_IPHONE_SIMULATOR=1

を、


OTHER_CFLAGS = -mno-thumb 

に戻す。



加えて、Debug Informationも弄る必要が有る


Debug Information Format = DWARF with dSYM File

になっているのを、

Debug Information Format = DWARF 

に変えるとOK。



最後の Debug Information Format 設定は、はじめから設定してしまっても良いかもしれない。


wrote 2012/12/01 12:03:18

Macでのフォルダごとの比較


概要

フォルダごとほうりこんで比較したい3000ほどのファイル/バイナリが生まれたので

なんかなーい? って社内に聞いたらいいの紹介されたので備忘録までに。



これ

DiffMerge

スクリーンショット 2012-12-01 1.45.46.png

DL

http://sourcegear.com/diffmerge/



Macだと10.6以降に対応。

Windowsにも対応。

そのほかにもなんか対応してたはず。



比較風景

フォルダ二個放り込んだら、こんな感じに差分があるファイルを見つけ出してくれる。

スクリーンショット 2012-12-01 1.38.38.png

バイナリも見てくれる。

各項目はクリックで開けて、文字列のファイル開いたりすると下記みたいな。

スクリーンショット 2012-12-01 1.39.56.png

バイナリファイルの比較は、違うのは判っても何処が、っていうのは無理っぽい。

スクリーンショット 2012-12-01 1.41.43.png

wrote 2012/12/01 1:36:25

さくらVPSで最低限セキュアな感じ + SFTP + Git + Jenkins


概要

ずっと放置してたVPS、隔離ラボ的な内容を試したくなってきたので、

纏めがてら実行してみます。



セキュリティ的したごしらえ

下記を参考に。

http://blog.myfinder.jp/2010/09/vpsssh.html



SFTP

下記を参考に。

http://lamp-oita.blogspot.jp/2012/07/vpssftp.html



Git

入ってた。

git version 1.7.1



Java

DLしてインストール

http://www.oracle.com/technetwork/java/javase/downloads/index.html

から落とした物を置いて、

sudo rpm -Uvh jdk-7u9-linux-x64-1.rpm



NginxとJenkinsインストール

インストール参考

http://blog.livedoor.jp/tattyamm/archives/4147336.html



Jenkinsにセキュリティ設定

参考

https://wiki.jenkins-ci.org/display/JA/Standard+Security+Setup


サインアップが終わったら、viewもサインアップも封印しておこうね!



JenkinsのGitプラグインを使う為にJenkinsのユーザーを変更

調整しておかないと、Jenkinsのデフォルトユーザーjenkinsではgitが実行できない。

code 128のエラーが出たりする。


/etc/sysconfig/jenkins の中の下記設定を弄る


JENKINS_USER="username"


//持ち主調整

sudo chown -R username /var/lib/jenkins

sudo chown -R username /var/log/jenkins

sudo chown -R username /var/cache/jenkins


//再起動

service jenkins restart



Jenkinsのコンソールで日本語が化けるので調整

/etc/sysconfig/i18n を開いて、

LANG="ja_JP.UTF-8"


とか書いておく。



動いた! やったねたえちゃん!

wrote 2012/11/28 18:23:24

MacJDK6以降のstdoutSJISになる現象の根源


概要

Tさんに粘着して教えていただいたので、纏めておく。

Tさんすいませんでした。


参考

http://happygiraffe.net/blog/2009/09/24/java-platform-encoding/



参考の意訳

不運にも、コマンドラインでJavaを実行する際、UTF-8文字列(U+00A9 COPYRIGHT SIGN[?])を渡したものをprintしたら、二重にエンコードされてしまった。


とりあえず-Dfile.encoding=UTF-8で対処していたんだけど、

自動リスタートとかしてたら、反映されない。これは不味い。

で、私たちは問題をさらに調査した。


-Dつけてれば適応されるんだし、きっとLANG環境変数が欠如している事と関係があるだろうな、とあたりをつけた。



試しに、システムプロパティ一覧を表示するアプリケーションを作って、結果をgrepしてみた。

おなじみのfile.encodingがある。さらに内部に、sun.jnu.encodingっていうのが有るのを見つけた。


で、-Dfile.encodingをつけての挙動を試してみた。

sun.jnu.encoding が変わってない!


このプロパティに関するドキュメントは、探してみたけど知る限りどこにも無いみたいだ。

実際の挙動を知る為に、JDK6のソースコードを読むしか無い。


main関数はjava.cにあった。実際に使われているJavaMain()関数の中身をみると、

NewPlatformStringArray()関数が定義されていて、コマンドラインからの入力行ごとに実行されている。

その中では、 new String(byte[], encoding)が呼ばれている。

さらにその中で呼ばれている getPlatformEncoding() 関数で、


System.getProperty("sun.jnu.encoding")



が呼ばれている。

このプロパティはどこでセットされているんだ?

System.cだ。


その中の Java_java_lang_System_initProperties() 関数の中で、

PUTPROP(props, "sun.jnu.encoding", sprops->sun_jnu_encoding);

という行があり、


sprops-> sun_jnu_encodingは、  java_props_md.c ファイル中の、

GetJavaProperties() 関数でセットされている。


こいつは、いろいろな環境変数を含んでいる。ロケールをコントロールするものも含めて。


「入力されるいろんなもの」から、sun_jnu_encodingを取得する為に設定されているみたいだ。


ちぇっ。

判った事として、次のパラメータが、 sun_jnu_encoding の定義に使われる。


Command line 引数

メインクラス名

環境変数



で、このパラメータはoverrideできる。

$ LANG= java -Dsun.jnu.encoding=UTF-8 -Dfile.encoding=UTF-8


訳終わり



という訳で

初期エンコーディングの可能性は、この java_props_md.c らへんを見れば判る、と。

http://hg.openjdk.java.net/jdk6/jdk6/jdk/file/536cbf2d9d0e/src/solaris/native/java/lang/java_props_md.c



GetJavaProperties メソッドの所には、

"Determine the language, country, variant, and encoding from the host"


って書いてある。これが元か。JDK5との比較しなきゃだけど、なぜこんな仕様になったんだろう。

インストーラの仕事サボった?


上からファイル追っていくと、sun.jnu.encodingの候補は、環境とかlocaleとかによってころころと変わっていく。

最終的に sun.jnu.encoding std_encoding の値を代入されるのだけれど、

std_encoding の値が下記のように変わる。



ISO8859-15 これはUS-ASCII


nl_langinfo(CODESET) こいつは langinfo.h / langinfo.c で定義されてる。 CODESETは環境によって異なる。

#ifdef __linux__


#define CODESET _NL_CTYPE_CODESET_NAME

#else


#ifdef ALT_CODESET_KEY

#define CODESET ALT_CODESET_KEY

#endif


#endif



ISO646-US 下記URLに色々載ってる。

http://www.asahi-net.or.jp/~yw3t-trns/code/iso646.html



ISO8859-1 Latin-1





さらに各環境の場合、下記がセットされる。


//en_UK だったら

ISO8859-1


//linuxだったら系

EUC-JP-LINUX 

eucJP-open

Big5_Solaris




で!

langinfo.c を探してみると、

すいませんよくわかりません。どこに有るんや。


下記適当に見つけてきた langinfo.c だと、localejpだったらSJIS返してる。

http://www.cl.cam.ac.uk/~mgk25/ucs/langinfo.c



続く。


wrote 2012/11/25 20:34:26

Macでメタセコイアを動かす


概要

OS X MountainLionで動かすことが出来るらしい!のでやってみた。



発端

スクリーンショット 2012-11-24 23.06.15.png

情報をくださった@kame0_0 さんに感謝!!

てっきりVMWareとか使ってなのかな~と思ってました。



DL

MikuInstaller

http://mikuinstaller.sourceforge.jp


今回の主役!

MountainLion X11 

http://xquartz.macosforge.org/landing/

MikuInstaller動作に必要。


メタセコイア

http://www.metaseq.net/metaseq/download.html


アドバイス通り、2.4 無償版を選択。


以前は有償版ライセンス持ってたんだけど、失くした。

いつだったかな、、、 4年くらい前じゃねーのかな。


ので、無償版でチャレンジ。



インストール

MikuInstaller

自分はMikuInstallerをApplicatiosにコピー。

スクリーンショット 2012-11-25 0.17.48.png

X11/XQuartz

スクリーンショット 2012-11-24 23.34.59.png

次に、MikuInstallerを起動 しゅらんみくさん。

スクリーンショット 2012-11-25 0.44.42.png

ツールバー内 プロセス > 実行

スクリーンショット 2012-11-25 0.23.01.png

ここから動かしたいプログラム(今回はメタセコ)の.exeを指定する。


指定すると、

スクリーンショット 2012-11-24 23.43.15.png

アプリケーションが起動! メタセコのインストール画面だ!

スクリーンショット 2012-11-24 23.43.20.png

インストール先は、 この写真では、適当にDesktopに一つフォルダを作ってやってみた。


この先で詳しく解説するけど、ここでの[インストール先]は、Windowsのアプリを展開する場所になる。

永劫使うので、位置が大事。


前もって、アプリケーション名のフォルダをApplications内に作って、それを指定するのが良いと思う。

この例では、Desktopにtestとか、適当なフォルダを作ったものとして、続ける。

スクリーンショット 2012-11-24 23.44.04.png

インストールを済ませると、

MikuInstallerがなにやら動き出す。

スクリーンショット 2012-11-24 23.51.16.png

で、MikuInstallerフォルダ下に、メタセコイアの.appが出来てる!!

スクリーンショット 2012-11-24 23.44.37.png

おおー。

ちなみにこの状態だと、.appは本当にMacのアプリケーション的な立ち位置の代物で、

どこに置いても動くっぽい。

起動してみると、

スクリーンショット 2012-11-24 23.44.50.png

ちゃんと動く!!

スクリーンショット 2012-11-25 0.04.35.png



注意点

・アプリケーションの本体について

アプリケーションの本体は、.app内には無い。

.appはあくまでもランチャー的な代物で、

アプリケーションそれ自体を.exeからインストールした位置に、本体がある。


MikuInstallerはその位置を覚えてる.exeをさらにX11で起動するためのランチャーを生成するプログラムみたいだ。

だったら生成される.appの中を指すように相対パスでインストールできればいいんじゃね?とか思う所だけど、

たまごが先かにわとりが先か的な感じになるので、むむむ。

.app生成に割り込めれば、、とか思うけど、大変そう。

.appの内容を解析したり、シンボリックリンクを喰わせるとかの手は使えそう。


あと、基本的に後の無いバッドノウハウだと思うので、

メタセコMac版を求め 目覚めた心が走り出したりする。


でもコレで、昔作ったモデルとかを変換するためにいちいちVMWareとか

立ち上げないでよくなる!!


アニメーションのキー付けあたりに無理があるらしいのだけれど、

そのへんメカニムでやっちゃうから平気!


という。


ありがとうございます!!

wrote 2012/11/24 22:59:45

デザイン/アイデア/技術/ニーズ、念願のアイスソードかどうか


概要

時々自分たちの議論のテーブルにのぼる話題として、

「それを自分たちがやって楽しいか?」っていうのがある。

思う所あったので少し。主観でしかない。


アイスソードあんまり関係ない。



コレは素晴らしいアイデアだ!!

「本当にそうか?

それは誰にとっての素晴らしいアイデアだろう?」


「利益がこれだけ見込める、こんなにユーザーがついてくるはず、etc。」


「そうかい。

で、それって僕らがやらないといけない事?


もっと言うと、それって僕らがやるべき、追うべき、楽しみながら続けられる事?


こんな会話を時々してる気がする。

内外問わず。主に外か。


否定ではなく、興味があるんだわ。

そのアイデアは、ちゃんと、いろんな照準をもっていて、

それぞれが出会ったものなのかどうか。



それは本当に念願のアイスソードですか?

ちょっと脇道に逸れて、いい○○って何だろう、的な話。


デザイン、アイデア、技術、といった言葉を、下記○○に入れてください。



何となくなんですけど、

「こんな○○出来た!! こんなこと出来そうだからやろう!!」

っていうのは、死の匂いがします。


技術だとNFCとか。もう最近でもないけど。

普及率とかとは別に、前後不覚になったボケ老人が骸をナデナデしてる感があります。



対でもなんでもないですけど、

「こんな○○があったのか!! これでやっとあの夢が叶う!!」

「こんな○○が出来た!! これでやっとあの夢が叶う!!」

っていうのは、とってもステキな夢の匂いがします。



何ていうか、素晴らしい普及をする「何か」には、ちょうどいい「邂逅点」がある気がするんです。

何の邂逅点か、っていうと、


叶えたい願い、解きたい問題、解きたい程度 を抱えている、当事者

と、

何かをなし得る○○

の、邂逅点です。出会うポイント、それぞれを中心とした円どうしが重なる特異点、って言っても良い。

このポイントがあるかどうか。っていうのが、ステキか、ステキでないか。

成し得る、というのは、ただのenabilityっていうか「可能にする能力」でしか無いので、

基本叶えたい人が一方的に「何かを成し得るもの」を探し、見つける話だと思っています。


ザックリ言うと、

何かをなし得る○○から、素晴らしさを享受する対象、当事者が存在するか? という事。

架空の使用者、数字の対象者でなく、自分たちがその当事者かどうか。

そして当事者として出会えたのかどうか。


出会えた自信が有るのなら、やっちまいましょう。

賛同者が居なくても大丈夫。


中には、未来生まれるであったろう問題点を、その問題点が生まれる前に抹殺してる、っていうド変態も居ます。

誰も頼んでなかったのに、「そう、これだよ!!」って言われる類いのモノたちです。

Appleとか。ディズニーとか。


すくなくとも作者が当事者属性持ってればOKなんじゃねーかなー。


「こんな無様な携帯電話使ってられるか、俺は理想のものを作り出すぞ、JoJo--!!!!」 的な。

「幻想がたりないでしょッッッッッッ!!!」的な。



駄目なデザインや技術やニーズは、その残念のど真ん中に「俺の考えたさいきょうのゆーざー」がいる気がします。

たいてい自分たち自身すらターゲットに含んでいない、マーケッターが弾いた数字から出す、ゴミみたいな何かです。


アイスソードを手に入れて、

「ねんがんの アイスソードを てにいれたぞ!」

こう言えるのは、ガラハドさんだけです。



我々の属性と、君が考えた素晴らしいことは、少なくとも数里先で邂逅してますか?

で、やっと話が戻るんですけど、


会社でやる場合、この中間点の話が、もう一歩複雑になるんだ、と思ってます。

簡単な話、登場人物に、「自分たちという会社」が増える。


組織体として目的があるし、それをする為にどんな組織かも存在するはずです。

ざっくりは。


このへんは、会社のアイデンティティーとか、Originについての話なんだと思う。

もし会社を擬人化したら、そいつがやりたがる事、とか考えると、想像するのがラクなのでは。


で、どうでしょう。

そのアイデア、会社さんとの邂逅点がありそうですかね? 好みそうですかね?



叶えたい願い、解きたい問題、解きたい程度 を抱えている、当事者

と、

何かをなし得る○○

と、

それが会社のアイデンティティー/Originと合っているかどうか


この三重の円の接点は有りますかね。


例えば本を通販で売る会社があって、アイデンティティーは「どんな手をつかってもこの本をユーザーの手元に」だったとする。

運送業しましょう! っていうアイデアが来たとして、これはまあ、合致しそう。


そうだね、確かに。僕らが運送もやれば、在庫管理しやすいし、客にもモノをより素早く届けられそうだ!

→後のAmazonである。 いや嘘ですけど。運送そのものはやってないです。 出だしはこんな感じじゃなかったでしたっけ。


今すぐ邂逅してる必要は無いし、最悪邂逅しなくてもやれば良いんじゃない?っていうのもある。

特に、数年後に邂逅するはずだから、やりましょう、とかは超萌える。


もしそれも無い場合、組織なんで、組織のOriginに反する/合流する予定も無いことは、させない方が良いんじゃないか。

って思う。


もしくはそこではないどこかで芽吹くべきものなんだろう、って。



ちなみに邂逅できなかったっぽい例で言うと、サービスとかだと上げやすいのでザクザクと、


AppleならPingとか、

GoogleならGoogle+とかAndroidとか。


「それって俺たちがやる必要あるの?」っていう問いに答えられる人が居るかどうか。

(いや実際は知らないよ? ただそう思えてならねーし今もってこの人たちがやる意味とか願望あるのかなーって思うだけ。)



Pingは、ユーザー間でのいいね! が育った所でAppleが得をするようには一切見えなかった。なぜ作ったし。

Google+は、今でも何の必要があってGoogleがやってるのか判んない。意図が見えねえ。得も見えねえ。

Androidは、、コレもGoogleがやる意図も得も見えねえ。

適当なVersionUpとか見てると、世界中の携帯機器メーカーとかデベロッパとかユーザーへのいじめなんじゃないか?

でもそう見ても意図がみえねえ。Win-Winの関係を持たない代わりに責任も持たないぜ、故に要求も却下、な関係。


邂逅する・しないに関わらず、やりたきゃやれば良いんだけどさ。

ただゴミ作ったり売ったりするのは勘弁な。


wrote 2012/11/18 19:03:33

MacでJavaのencodingがSJISなのを起動時に対処


概要

JDK5まではUTF-8だったJavaのencoding、

JDK6からはSJISに。

https://blogs.oracle.com/katakai/entry/netbeans_and_java_for_mac2


死ね!! SJIS死ね!!!


いままで全く気にしてなかったんだが、原因調べてみたいんだけど、

Macからは特になんも指定してないような感じ。JDKのほうのデフォルトの変化か何かなのかな? 諭してくれ神々よ。

すくなくとも日本語でっせ! みたいな情報がJVM使う際にわたってると思うんだけど。

それかinstall時かな?



で、結局文字化けして困るよね!

っつーのを、launchctlを使って解決する方法があったので纏める。


環境は

スクリーンショット 2012-11-11 15.02.41.pngスクリーンショット 2012-11-11 15.03.33.png



いままでの自分の対処法

JDK6以降をそのまま使うと、例えば対処してないツールからJavaとか使ったときに、

マルチバイトな部分が全部文字化けする。

対処方法として、今まで下記を使ってきた。


・ツールの起動時に

export _JAVA_OPTIONS=-Dfile.encoding=UTF-8


とかやる


これがまあ、、、効かせやすいツールと効かせにくいツールが有るわけで。


大概Terminalから実行するCUIのツールだったら、Terminal自体の設定として

上記を実行して済ませてきた。bashの設定に書いたりとか。


ただコレだと、Terminalから起動すればその設定が受け継がれるだけであって、スマートな方法ではない。

(そも受け継がれないこともある)

JAVA_OPTIONS自体、JVMへとパラメータを渡す際のものなので、ひょいひょい渡しているのも気に喰わない。


ずーっと代案探してたんだけど、ステキな事を考える人は居るもので。



ステキな対処法

Setting environment variables in OS X?

http://stackoverflow.com/questions/135688/setting-environment-variables-in-os-x/588442#588442


launchctlが起動時に触るファイルを、

/etc/launchd.conf

として作ってしまい、その中に起動時の設定を書いてしまおう、というもの。


launchctlの日本語資料で一番いいのはコレ。

maruko2 Note

LaunchDaemons (launchctl, launchd.plist) の使い方

http://bit.ly/TlRXcn


このStackoverflowの記事中で弄っている項目自体はかなり物騒な感じなのだけれど、

自分がやりたいのはencodeをUTF-8にするだけなので、

setenv JAVA_TOOL_OPTIONS -Dfile.encoding=UTF-8

とだけ書き込んでマシン再起動。ログオフでもいいかもしれない。


で、たとえば

java -h

highvision:~ sassembla$ java -h

Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8

使用方法: java [-options] class [args...]

           (クラスを実行する場合)

   または  java [-options] -jar jarfile [args...]

           (jarファイルを実行する場合)

optionsには次のものがあります。

    -d32   使用可能な場合は32ビットのデータ・モデルを使用する

    -d64   使用可能な場合は64ビットのデータ・モデルを使用する

    -server   "server" VMを選択する場合

                  デフォルトVMはserverです,

                  これはサーバークラスのマシンで実行しているためです。



    -cp <class search path of directories and zip/jar files>

    -classpath <class search path of directories and zip/jar files>

                  クラス・ファイルを検索するディレクトリ、

                  JARアーカイブおよびZIPアーカイブの:で区切られたリストです。

    -D<name>=<value>

                  システム・プロパティを設定する

    -verbose[:class|gc|jni]

                  詳細な出力を行う

    -version      製品バージョンを出力して終了する

    -version:<value>

                  指定したバージョンを実行に必須にする

    -showversion  製品バージョンを出力して続行する

    -jre-restrict-search | -no-jre-restrict-search

                  ユーザーのプライベートJREをバージョン検索に含める/除外する

    -? -help      このヘルプ・メッセージを出力する

    -X            非標準オプションに関するヘルプを出力する

    -ea[:<packagename>...|:<classname>]

    -enableassertions[:<packagename>...|:<classname>]

                  指定した粒度でアサーションを有効にする

    -da[:<packagename>...|:<classname>]

    -disableassertions[:<packagename>...|:<classname>]

                  指定した粒度でアサーションを無効にする

    -esa | -enablesystemassertions

                  システム・アサーションを有効にする

    -dsa | -disablesystemassertions

                  システム・アサーションを無効にする

    -agentlib:<libname>[=<options>]

                  ネイティブ・エージェント・ライブラリ<libname>をロードする。例: -agentlib:hprof

                  -agentlib:jdwp=helpと-agentlib:hprof=helpも参照

    -agentpath:<pathname>[=<options>]

                  フルパス名でネイティブ・エージェント・ライブラリをロードする

    -javaagent:<jarpath>[=<options>]

                  Javaプログラミング言語エージェントをロードする。java.lang.instrumentを参照

    -splash:<imagepath>

                  指定したイメージでスプラッシュ画面を表示する

詳細はhttp://www.oracle.com/technetwork/java/javase/documentation/index.htmlを参照してください。

みたいな感じになった。

ステキ。



副作用

あんまり思いつかないけど、SJISで動かしてる人にこのテロすると、どこにかいてあるんだか迷わせることができて邪悪。

launchctl周りは情報少ない気がする。



おまけ

JVMのパラメータいろいろが見やすく紹介されてるサイト見つけた。

http://javarevisited.blogspot.jp/2011/11/hotspot-jvm-options-java-examples.html

wrote 2012/11/11 4:44:37

第0回 Sublime Text 2 勉強会に行ってきた


概要

弊社社内の公認テキストエディタの座をTextMateシリーズから勝ち取ったSublimeText2。

の、勉強会がサイバーエージェントさんであったので、LTで参加させてもらいました。



URLS

ATND

http://atnd.org/events/33305

Togetter

http://togetter.com/li/403472


UST(あったのか、、!!)

http://www.ustream.tv/recorded/26772975


当日の内容


Sublime Text 2ことはじめ 

こもりまさあきさん @cipher 

PackageControlのインスト、使い方のベーシックなところをサクサクと。

command + shift + pは慣れると手放せないっすよねー。

あの虫眼鏡的なツールが気になる。



プラグインの作り方 

@blueplanet42 さん

http://blueplanet.github.com


プラグインの作り方の解説。

Octopress知らんかった。 このブログっぽいもの と概念似てるかも。


プラグインをホストするGithubのリポジトリ名と、プラグインには、

別名称をつける事が出来る!

→書く所が有る


これは知らんかった。

ステキ。



Text Editor Anywhereでtextareaもsublime text 2(Windowsのみ!)」

@maepon

岡山からハングアウトでLT。

Anywhere、Windows8に入れて試してみよう。



IMESupprt for Sublime Text 2 / ConvertToUTF8

@kiyokura

同岡山からハングアウト。

Windows系だと日本語がインライン展開できない、という問題に対するプラグインとか!

これでWindowsPhone8用の開発環境でもST2使えるわー。


ConvertToUTF8 はVS SJISに使えそう。


Emmet

@sada_h

ZenCoding的なプラグインの紹介。

ST2のマルチカーソルと合わせると確かに編集速度がくそっぱやい。


あとSublimeServer便利。



Gradle

自分。

GradleをST2から使う奴。


LT死霊

http://bit.ly/TtVOBD


サンプルプロジェクト(gradleがインストールされてる前提で動くVer)

http://bit.ly/PWhThE


サンプルプロジェクト2 (gradleがインストールされてなくても動くVer)

http://bit.ly/RKxlKr



SUBLIMETEXT PLUGINS INTRO

@agektmr

http://www.rvl.io/agektmr/sublimetext-plugins-intro


有用なプラグインの紹介連発。

SublimeCodeIntel

LESS-build

FileDiffs

Diffs便利よなー。



おつかれさまでした!

いろんなプラグインが知れてウハウハでした。

wrote 2012/11/07 17:50:34

SublimeText2のプラグインを作る時のまとめ


概要

プラグインを作るときに、自分が調べて学んだこととか

調べ方とかを纏めておく。



参考にしたもの

なにはともあれまずAPIと、

http://www.sublimetext.com/docs/2/api_reference.html


作り方

http://net.tutsplus.com/tutorials/python-tutorials/how-to-create-a-sublime-text-2-plugin/


あと今まで使ってたプラグインを、参考までに開けて見てた。全部Package Controlに入ってるはず。

感謝。


InsertDate

どっちかっていうとPythonの勉強になった


Package Control

UIの勉強に超なった


Git

Gitの勉強になった

Scalariform

コマンドライン実行の勉強になった


commandについて

SublimeText2でよく見る、実行プロトコルみたいなもの。

値の名前がついてるPythonプログラムを実行する。 

JSON内で定義されている事が多いが、.py内から他のcommandも呼べる。


例えば、


"command": "myCommand"


とか書いてあると、


myCommand って名前をつけられてる特定条件を満たした.pyプログラムが実行される。


特定条件

command : コマンド名 に対して、


・このプラグインフォルダ中に、コマンド名を含んだclass が定義されている.pyファイルがある

.pyファイルならファイル名は何でも良くて、class名がコマンド名を含んでいるのが条件。

command : something なら、 SomethingHappen とかになる。


注意点として、cammelケースとかがあると、混乱のもと。


command : somethingelse とあったら、


class SomethingElse だと ×。

class Somethingelse で ○。 一度ハマった。


・その class が、次のどれかのSublimeのクラスを継承している。

sublime_plugin.ApplicationCommand

sublime_plugin.WindowCommand

sublime_plugin.TextCommand


それぞれの違いはAPIみてくだしあ。

http://www.sublimetext.com/docs/api-reference#sublimeplugin.Plugin


当然 import も必要。


・run メソッド(特定引数あり)を持っている

引数は上記クラスによって異なる。


各条件を満たした.pyの表記はこんな感じ。

.pyファイル

import sublime

import sublime_plugin


class コマンド名を含んだクラス名 (sublime_plugin.TextCommand):

  def run (self, edit) :



プラグイン基礎構造

プラグイン名のフォルダ

+-syntax

+-Default.sublime-commands

+-Default.sublime-keymap

+-Main.sublime-menu

+-プラグイン名.sublime-settings

+-その他 .pyとか、README.mdとか



何を変えるとどこが変わるのか

プラグインの中のファイル一覧と、その内容についての記述が無かったのでメモ。



Default.sublime-commands

commandの基礎リスト。

⌘ + shift + pから出てくる、プラグインに含まれてるcommand一覧が書いてある。

commandの条件を満たせば表示される。


Default.sublime-keymap

キーバインド、ショートカットとcommand(ST2での標準的な実行形式)の連携を書くファイル。

こんな感じ。

[

{ "keys": ["super+alt+b"], "command": "gbuild" }

,{ "keys": ["super+alt+t"], "command": "gtest" }

]

内容がすでに用意されている物とかぶると、上書きしちゃったりされちゃったりする。

ところで現在インストールされてるキーマップ一覧をチートシートみたいに表示するプラグインが欲しい。。



Main.sublime-menu

Toolsなど、Sublime上部のバーで表示する要素に追加する項目を記述する所。

jsonでの階層構造、とても奇麗。//でコメントが使える。

[

    {

        "id": "tools",

        "children":

        [

            {

                "caption": "Gradle",

                "children":

                [

                     { "caption": "Log", "command": "test" }

                ]

            }

        ]

    }


    ,{

        "caption": "Preferences",

        "mnemonic": "n",

        "id": "preferences",

        "children":

        [

            {

                "caption": "Package Settings",

                "mnemonic": "P",

                "id": "package-settings",

                "children":

                [

                    {

                        "caption": "Gradle",

                        "children":

                        [

                            {

                                "command": "open_file",

                                "args": {"file": "${packages}/Gradle/Gradle.sublime-settings"},

                                "caption": "Settings – Default"

                            },

                            {

                                "command": "open_file",

                                "args": {"file": "${packages}/User/Gradle.sublime-settings"},

                                "caption": "Settings – User"

                            },

                            { "caption": "-" }

                        ]

                    }

                ]

            }

        ]

    }

]


とか書くと、①Tools の項目にGradle、さらにその要素として Log が表示される。



③Preferences > package Settings に表示される際の名称。アプリの設定(Preferences)から選択できる。

だいたいのプラグインは、ここから設定ファイル ④、⑤プラグイン名.sublime-settings を開けるようにしているみたい。


メニューの項目はネスト可能で、ネストした場合、プルダウン表示される。

スクリーンショット 2012-11-02 2.27.54.png

簡単に作れて素敵。



Side Bar.sublime-menu

サイドバーで、メニュー表示時に表示される内容が書き足せる。

jsonでの階層構造、とても奇麗。コメントが使える。


プラグイン名.sublime-settings

設定ファイル。

プラグインのデフォルトがプラグインフォルダにあり、

上書き用の同名のファイルがSublimeのUser フォルダ下にあるのがコモンセンスらしい。



プラグイン製作中のSublimeの挙動について

control +  ` でSublime内のPythonコマンドライン窓が出るんだけど、

プラグインのファイルを編集→保存、とかやると、

[Reloading plugin /Users/sassembla/なにやら] とか表示されるので、プラグインは都度更新、ビルド、再読み込みがされている。



.pyファイルについて

プラグインのフォルダ内に存在してれば読み込まれる。



Toolsからのプラグインのcommandの実行について

[

    {

        "id": "tools",

        "children":

        [

            {

                "caption": "Gradle",

                "children":

                [

                     { "caption": "Build", "command": "build" }

                ]

            }

        ]

    }



①、②で、ToolにGradleメニューが現れるようになるが、

③のtest commandがちゃんとToolsからハイライト表示されるかどうかは、


commandの条件を満たす必要がある。


条件を満たさない場合、commandは灰色で表示され、実行できない。


実際の挙動を作る

具体例はちょっと思いつかないので、仮の例を挙げる。

・とあるプロセスをSublimeText2から実行したい


たとえばTypeScriptのテスト(って何まだ無いけど)を実行したいとか、

JenkinsのトリガーをSublimeText2から引きたいとか


そんな感じの物事があったとして、

「無事にPlugin作りました、簡単です、実行できます!」


→いざ実行→UIがロックされる

と殺意を覚える。コンマ一秒でもUIをロックしちゃだめだ。。。 

→できるだけ非同期に行って、でも結果はUIに返そうぜ!


そんなときは次の機能のペアが役に立つ。


threading.Thread


sublime.set_timeout(callback,  delay)


Androidやってる人ならピンと来るかもしれない。

iOSやってる人には全くピンと来ないと思う。

JSerな自分はJSな理解で誤解した。


threading.Thread は

スレッドです。


PythonのAPIに入ってるので調べてくだしあ。

このへん

http://docs.python.org/2/library/threading.html

http://www.doughellmann.com/PyMOTW-ja/threading/



sublime.set_timeout は

特定動作を指定時間後に実行する。


SublimeTextのAPIに含まれている。

http://www.sublimetext.com/docs/2/api_reference.html

このAPIは、

特定の関数(callback)を、delayミリ秒後にMainThreadで実行する

っていう感じのものになる。

"It is safe to call setTimeout from multiple threads."


この一文から解れってのが、ちょっとキツい。


これらを使って何をすると捗るか:

スレッド立ち上げてなんらかの処理を実行、

UIをロックせず、

終わったらUIに通知

というのが、この2つの組み合わせで出来る。

とても捗るのでお薦め。



以下おまけ話

よくあるクライアントサイドアプリの話として、

UIをもつアプリケーションは、須くUIを扱うThreadを持つわけで、

このUIThreadへのアクセスができないと、GUIになんにも反映できない。

良いプラットフォームはこのへんの隠蔽が上手。

SublimeText2だとどうなっているのか。


例えばSublimeTextのAPIに含まれている次の関数

status_message(string)


なんかは、stringに入れた内容をSublimeText2の最下部のバーに表示できるんだけど、


UIの要素なので、

UIThread(っていうかMainThread)からしか呼べない。

適当にThreadを継承したクラスを作って、インスタンスつくって、

インスタンス内でstatus_messageメソッドを呼ぼうとすると、Assertionで殺される。

たとえばこんなソースを書いたとする

    #どっかでスレッド継承クラスをinstantiateして、start

    thread = SomeThread("hahaha!")

    thread.start()


#スレッド継承クラス

class SomeThread(threading.Thread):

  def __init__(self, message):

    self. message = message

    threading.Thread.__init__(self)


  def run(self):

    print "run start, message is ", self.message

    sublime.status_message(self.message)


こいつは、次のエラーを呼ぶ。

Exception in thread Thread-397:

Traceback (most recent call last):

  File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/threading.py", line 532, in __bootstrap_inner

  File "./testing.py", line 40, in run

    sublime.status_message(self.command)

RuntimeError: Must call on main thread, consider using sublime.set_timeout(function, timeout)

(MainThread外から呼んでんじゃねーよksg!! set_timeout使え!!)


で、言われた通り、sublime.set_timeout を使うと、問題なく該当メソッドが呼べる。


delayミリ秒後、timeout先で呼ばれるのがmainThreadになっている、という絡繰り。

関数をぶん投げて、MainThread で実行される。



Androidだと、実行したい処理を含んだThreadを作ってrunOnUiThreadメソッドにThread放り込んで云々、って感じになるところ。

iOSだと、そもそもそんな残念な苦労はしなくてよくて、UIViewのクラスメソッドや、セレクタ渡しや、NSNotificationが超強力になんとかしてくれる。

JSだとそもThreadって概念無いので、はい。


Sublimeは、っていうと、だいたい上記のメソッドで、優雅では無いけど使いやすい感じに仕上がっていると思う。

せめてrunOnMainThread と runOnMainThreadWithDelay とかに出来なかったのか、、とか思うが、


関数そのまま渡せるのですっごく助かる。



メモ


OS判定

デフォルトでOS判別をしてくれてる。

詳しくは @ikeike443 さんのScalariformとか読むと良いと思う。

ikeike443 / Sublime-Scalariform

https://github.com/ikeike443/Sublime-Scalariform


Terminalみたいに何かを実行したいんだけど。

コマンドラインを実行するには。


self.view.window().run_command('exec', {'cmd': ['sh', 'script.sh'], 'quiet': False})  

→viewが存在するメインスレッドからのみ実行できる。

実行中の内容がPromptっぽいWindowで表示できるんだけど、Mainをがっちり掴んでしまう。

スレッド違いには出来ない。UIが絡んでるからだね。


subprocess.call(self.CMD+self.view.file_name(), shell=True)

→別スレッドでも実行可能。

Python API

http://www.python.jp/doc/release/library/subprocess.html

なんだかんだで Popen が無双。

SublimeText2の現在のデフォルトがPython2.6系なので、

check_outputが使えないのが残念。



viewの再描画

self._force_refresh()

強制読み直し



Toolでのプラグインの実行表記に、ショートカットが勝手についた  \(^o^)/わーい

プラグイン作ってる途中になんか、勝手についちゃった。

本来は、 Default.sublime-keymapに書かなければつかない、、はず、、


勝手にショートカットついちゃった//// 流石俺/////

スクリーンショット 2012-11-03 22.22.01.png

→なぜなんだぜ

→build というcommand名を用意していたんだが、それが不味かった。


デフォルトで存在するcommnd名 build とモロかぶりした。



デフォルトで存在するcommnd名を自作プラグインが定義してしまうと、プラグインのもので上書きされる。


で、デフォルトのbuildには、super + b というキーが Default.sublime-keymapで セットしてあったので、

基礎定義部分だけプラグインがオーバーライドして、表記などは Default.sublime-keymap のものが採用されてた、という。


部分オーバーライド(?)こええ。



ショートカットについてのハマりどころ

super + alt + t を とあるcommandのショートカットに指定してたんだけど、

スクリーンショット 2012-11-05 14.16.27.png

commandPaletteからは表示されるのに、

スクリーンショット 2012-11-05 14.16.53.png

Toolsからは表示されなくて

スクリーンショット 2012-11-05 14.18.19.png

「、、、何でなんだぜ、、? 一方では出て、もう一方で出ない、、強制上書きが発動しているはず、、では、、?」


って思ってたんですけど、これ、上書き不可とかも有るみたいですねー。

super + alt + tは、こいつだった。

スクリーンショット 2012-11-05 14.21.03.png

試しにcommand + alt + n に変更したら、commandPaletteの方も、Toolsのほうも、

ちゃんと表示されました。


泣いてません。



wrote 2012/11/01 10:21:12

語源が好きです。でも厨二な語源がもっと好きです!


概要

Twで語源を紹介するサイト

http://gogengo.me

の紹介をしてもらって、これは素晴らしい! と思うなど。


ついでに、今まで知りたかった


mute mutable は意味が真っ向から激突してる気がするんだがスペル似てるしどうなってるんだろう」

という悩みを解消すべくフワフワしてみた。


過程でいろいろ面白い「英語について調べる系」Webサービスを紹介してもらったりしたので、

まとめまでに。



visualthesaurus

http://www.visualthesaurus.com/landing/

pronunciationと語の意味的なつながりが図を見ながら知れて便利。

スクリーンショット 2012-10-28 16.59.49.png



THE FREE DICTIONARY

http://www.thefreedictionary.com/

標準的な辞書サイト。


online etymology dictionary

http://www.etymonline.com/index.php

名の通り、ことばの語源、成立時期をみるのに便利。

一体どうやって調べてあるのやら。


成立時期が熱い、、、!!!



vocabulary.com

http://www.vocabulary.com/dictionary/


言葉の意味の浅いルーツが知りたければこのサイトが便利。

例文とかが新聞。



Oxford Dictionary of English

今回のMVP


Macの辞書を起動 > メニューの「辞書」 > 環境設定 

スクリーンショット 2012-10-28 20.50.44.png

あったわー、、 チェックを入れると、辞書として選択できるようになる。

スクリーンショット 2012-10-28 20.54.33.png

うーん、買わなきゃいけないかと思ってた。

っていうかAppStoreにあるのが怖い。厭な予感がする。


終わりに

とりあえず俺の疑問は解消した!

mute mutable は語源から違う全然関係ない言葉だった!


もうなにも怖くない!

wrote 2012/10/28 17:49:28

フォルダをFinderからSublimeText2で開くアプリ作った


概要

特定のフォルダをSublimeText2で開きたい、そんな時に使えるはず。

https://github.com/sassembla/SublimeHere



インストールとか

SublimeText2が事前にApplicationフォルダにインストールされてるのが前提です。

githubからアプリケーションをDLして、入ってる

SublimeHere.app アプリを Applicationフォルダに叩き込んでください。


そしたら、下図のように SublimeHere.app をD&Dしれ。


スクリーンショット 2012-10-24 1.07.20.png


使い方

クリックするとそのフォルダでSublimeText2が起動します。 こんな感じになってるフォルダがあったら、  (写真のSublimeHere.appのアイコンは弄ってます)

スクリーンショット 2012-10-24 1.32.46.png

このフォルダをルートにしてSublimeが起動します。

スクリーンショット 2012-10-24 1.32.50.png

アイコンの変え方

右クリックでアプリケーションの中身がガンガン見れると思うので

Resources の中の .icns ファイルを好きなのに変えてくださいな。



謝辞

Original idea of this app is the below apps.

http://manas.tungare.name/software/finder-apps/


NOTE: these apps are not work on MacOSX Lion and later…


wrote 2012/10/24 0:53:06

メモ:TypeScript 0.8のコンパイルオプション集


概要

TypeScriptハッカソンで、

TypeScriptCompilerのソースコード見たらかいてあったのと、

ほかにどこで見れるのかわからんかったので列記。


-なのか --なのかは書いてないのでなんだ、アレだ、頑張ってください。



'out'

    usage: 'Concatenate and emit output to single file'

ファイル出力、一つに合成した状態のファイルが出る。

ファイル名は指定したものになる。


'style'

    usage: 'Select style checking options (examples --style requireSemi:off or --style "eqeqeq;bitwise:off")'

        使ってないからわかんない。


'sourcemap'

    usage: 'Generates corresponding .map file'

ソースマップが出る。ファイル名は、~.js.map になる。

        

'declarations'

    usage: 'Generates corresponding .d.ts file'

.d.tsファイル吐く

        

'reference'

    usage: 'Add a reference to the compilation'

使ってないからわかんない。


'watch'

    usage: 'Watch output files'

使ってないからわかんない。


'exec'

    usage: 'Execute the script after compilation'

使ってないからわかんない。


'parse'

    usage: 'Parse only'

使ってないからわかんない。

        

'minw'

    usage: 'Minimize whitespace'

使ってないからわかんない。space取るのか、、文字列実行する系と相性わるそう。


'const'

    usage: 'Propagate constants to emitted code'

       使ってないからわかんない。


'errorrecovery'

    usage: 'Enable error recovery'

使ってないからわかんない。


'comments'

    usage: 'Emit comments to output'

コメントを残す


'cflow'

    usage: 'Control flow'

使ってないからわかんない。


'cflowp'

    usage: 'Print control flow'   

使ってないからわかんない。


'cflowu'

    usage: 'Print Use Def control flow'

使ってないからわかんない。

        

'noerroronwith'

    usage: 'Allow with statements'

使ってないからわかんない。

        

'noresolve'

    usage: 'Skip resolution and preprocessing'

使ってないからわかんない。

        

'debug'

    usage: 'Print debug output'      

ビルド中の悲喜こもごもが出てた

        

'canCallDefinitionSignature'

    usage: 'Allows you to call the definition signature of an overload group'

使ってないからわかんない。


'nooptimizemodules'

   usage: 'Do not optimize module codegen'

使ってないからわかんない。

        

'nolib'

    usage: 'Do not include a default lib.d.ts with global declarations'

使ってないからわかんない。

        

'inferProperties'

    usage: 'Infer class properties from top-level assignments to \'this\''

使ってないからわかんない。

        

'target'

    usage: 'Specify ECMAScript target version: "ES3" (default) or "ES5"'

使ってないからわかんない。

        

'module'

    usage: 'Specify module code generation: "commonjs" (default) or "amd"'

使ってないからわかんない。

            

'help'

    usage: 'Print this message'

すくなくともここにある情報は吐いてくれなかったよね、、、

    

'useCaseSensitiveFileResolution'

    usage: 'Force file resolution to be case sensitive'

    使ってないからわかんない。



以上。

wrote 2012/10/20 22:46:41

TypeScriptハッカソンに参加してみた

概要

Sublimeのpluginを整理しつつ、

TypeScriptをビルドしたときのエラーをそのままSublime内に表示したり、

GradleからTypeScriptをビルドしたりテストしたりするにはどうすればいいのかなーと

考えてました。



Sublimeへの簡単なInstallation

前提

nodeが入ってる

brewとかで、nodeが入ってる


nodeのinstallとか

http://shapeshed.com/setting-up-nodejs-and-npm-on-mac-osx/


tscが入ってる

nodeのプラグインとしてのTypeScriptのビルドツール

http://www.typescriptlang.org/#Download

まずは

SublimeのbuildSystem設定 + syntaxHighlight設定 の入ったこのプラグインを入れる

"A simple package for Sublime Text 2

that includes syntax highlighting and a basic build system"

https://github.com/eranation/sublime-text-2-typescript

SublimeのpackageControlには入ってないので、githubからcloneして


/Users/USERNAME/Library/Application Support/Sublime Text 2/Packages

にTypeScriptフォルダを入れるだけ。



で、本題のSublimeTextからビルドしたあとに、エラーをSublimeに表示する感じのやつ

SublimeTextには、


Writing: (:scala-notes (:is-full nil :notes ((:severity error :msg "value !! is not a member of com.kissaki.MessengerActor" :beg 7689 :end 7701 :line 346 :col 40 :file "/Applications/eclipseScala/scalaworkspace/MondogrossoProcessOrders/src/com/kissaki/Messenger.scala"))))


みたいに、特定の文字をバッファに入れると、エディタに表示してくれる機能がある。

(ENSIMEがensime.elでそんなかんじにやってた。)

こんな感じに見れる


結局、時を経て完成した。


SublimeSocket + TypeScript ~さよなら! node.js強依存~ 編

http://sassembla.github.com/Public/2013:04:03%202-27-52/2013:04:03%202-27-52.html

wrote 2012/10/20 13:44:00

Sublimeで動くGradleショートカットを雑に作る


概要

SublimeTextからGradleを動かすプラグインが見つけられなかった、、

ので作った。


っていうか超簡単に雑な感じのが作れたのでお茶濁しまでに。


2012/10/19 0:43:17

githubに上げるようなとこまでやってなくて、とりあえずコマンドとして

走らせられるようにしただけ。


完全固定で特定のtaskを実行するだけ、めっちゃ手抜きです。


そのうち、build.gradleの特定の行のコマンドを実行、とか、、

やるかもやらないかも。



前提

Gradleをhomebrewとかで入れてある。

= /usr/local/bin に gradleのショートカットがある、、とする。


べつのとこにあってもパス変えればOK。

スクリーンショット 2012-10-19 0.44.19.png



作成開始

Sublimeを起動した状態で、トップのバーの

Tool > Build System > New Build System...

スクリーンショット 2012-10-19 0.47.13.png スクリーンショット 2012-10-19 0.47.20.png(ここでもうgradleがあるのはすでに作っちゃったから。)



するとこんな感じに、ビルド設定ファイルのひな形が開くはず。

スクリーンショット 2012-10-19 0.47.32.png

ここに設定を書けば、command + b で実行できるぜ、と。

で、下記のように書いて、

{

"cmd": ["/usr/local/bin/gradle test -d"],

"file_regex": "build.gradle",

"selector": "build.gradle",

"working_dir": "${project_path:${folder}}",

"shell": "true"

}

お察しのように、めっちゃ単純です。

プロジェクトのフォルダがある階層のbuild.gradleに、test -d をそのままぶちこんでます。


で、保存。 このときの名前が Build System の一覧に出ます。

スクリーンショット 2012-10-19 0.54.50.png

保存場所は一定で、/Users/だれだれ/Library/Application Support/Sublime Text 2/Packages/User

に出来る。


で、Tool > Build System から該当のを選択した上で、command + b でビルドできる。

らくちん。

スクリーンショット 2012-10-19 1.01.29.png

あ、テスト失敗。



ぱっと作った上での課題

まず「これbuildでやることか?」ってのがある。すいません簡単そうだったんで試したかったんです。


あと、

どうも、build で実行されてるプロセスは、Sublimeにけっこう組み付いた状態で実行されてるらしくて、

重い処理を実行するとSublimeも引っ張られて挙動が鈍化する。


試しにSpecs2で1000くらいのテスト並列実行ってやったら、全く操作できなかった。


build以外で、外部プロセスにしたりすれば軽いと思うんだけどな、、


今後、プラグインで別プロセス、というのを試すつもり。


wrote 2012/10/18 23:59:10

ScalaでActorを使ったメッセージパッシング便利化ライブラリを書いてみた


(旧)ScalaBaseに行けないエントリ (駄目な事書きすぎで事務所的にアウトが出ました)


概要

メッセージパッシング便利化ライブラリ作った

ScalaMessengerPrototype

https://github.com/sassembla/ScalaMessengerPrototype



Scalaで標準に用意されているActor(2.9.2までなのでActors)

http://www.scala-lang.org/api/current/scala/actors/Actor.html


を、特にclass間のmessagePassingに使用するために使いやすくしたつもりのライブラリ。

ちょうど2.10がそろそろ出るぜ的な話があったので、

Akkaに取って替わられるActorsにお別れを言いがてら作ってみた。



コンセプト/要件定義


MessagePasingが、特定のフォーマット+小さな手続きで使用/送受信可能


要件

・Javaから使える/Scalaから使える

・通信内部は全部Actors、Akka版へのリプレースを考慮に入れる

・同期、非同期でのメッセージ送付/受信

・ネスト呼び出し可

・ブロードキャストあり

・通信が可能な対象を明示する機構

・メッセージラベルの付与

・可変長引数でのオブジェクトの送付

・テスト書く

・動作にかかるコスト、処理のチューニングは無視



オリジナルは、Objective-CのNSNotificationを使ったもの。


このへん。

https://github.com/sassembla/MessengerSystem

注:古いです。ARC対応してません。ぶっちゃけARC対応した最新の社内版があるのだけど、特化しすぎてて出せない。



コレを使うと何がどう楽になるの?

メッセージパッシングのそもそもの利点として、

pointer/参照を持たないオブジェクト同士が、物を投げ合ったりする事が出来る


っつーのがあるのですが、

ただ、Actorsそのままだと、毎回定義するものが多かったり、case class作りまくらないといけなかったりで、めんどい。


なので、

数行書けば使える

みたいな目標をたてて、一通りMessagePassingが、

特定のフォーマット+小さな手続きで使用/送受信可能になるように、作ってました。


実際、Javaからだと6行くらい、Scalaからだと4行くらい書けば使えます。



列挙すると

①特定フォーマットでメッセージを送れる


def call(targetName : String, exec : String, message : Array[TagValue])


targetName

メッセージ送付ターゲットの識別子、メールでいうところのTo


exec

メッセージの識別子、メールでいうところのタイトル


message

可変長引数のkey-valueペア。本文みたいなもの。



②特定の受信箇所に届く(必ず書かなきゃいけない)

/**

* Childのレシーバ

*/

@Override

public void receiver(String exec, TagValue[] tagValues) {

.......


無いとコンパイルとおらない。



サンプルコード


Javaから使う

https://github.com/sassembla/ScalaMessengerPrototype/blob/master/sample/sampleJava/com/kissaki/Parent.java


https://github.com/sassembla/ScalaMessengerPrototype/blob/master/sample/sampleJava/com/kissaki/Child.java



Scalaから使う

https://github.com/sassembla/ScalaMessengerPrototype/blob/master/sample/sampleScala/com/kissaki/Parent.scala


https://github.com/sassembla/ScalaMessengerPrototype/blob/master/sample/sampleScala/com/kissaki/Child.scala




制約

PROBLEM:

pointerに依存せずに自由に物を送り合う事が出来るので、自由にやり過ぎるとカオスになる

受信者の名前だけを指定して送る形式だった時代があって、誰が誰に何を送ってるかがカオスになった。


SOLUTION;

明示した関係の間柄でしか、送付しあえないようにする



具体的には→


[親子関係がある間柄しかmessageを送付しあえない]という制約を勝手に作っている。



下記シークエンスで成立させてる。


・messengerが各自なまえを持つ

・子どもになる予定のmessengerからinputParent(親名称)で仮親を名前で指定

・親予定のmessengerが受信、条件を満たしていたら子予定を子どもとして認定、子どもに返信

・親子関係成立



→制約が有る上でのデメリット

・誰にでも送る、という動作ができなくなった

・本来余剰な機構なので重い



→制約がある上でのメリット

・誰に送るつもりか、コードの特定の箇所をみればわかる


デメリットの方が多いんだけど、複数人で使う上では、メッセージの方向の明示性は必須仕様だった。



MessagePassingで書くと楽なこと

・オブジェクト間の関係性をPointerとは無関係に再構築可能

Pointerでの構造的な構築とは別に、任意の意味的な関係の構築が可能。

既存の手段 : PointerでのObject所持、メソッド実行

に、

新手段 : MessagePassingでの関係構築

が加わる感じ。

道具が増える分だけ、明示できるものが増える。


・粗結合

MessagePassing自体の前提なので、コレを使って使われているライブラリとかモジュールも、粗結合にできる。

さらに言うとしやすい


・意味の付加が可能

発生させるメッセージを「イベント」だとすると、下記みたいな表記の発信と受け取りが可能。


リロードボタンが押されて、表示データが更新される


(ビュー:タッチが発生

→この部分はだいたいの仕様で暗黙のはず)


→ビューコントローラ:タッチイベントが発生

→RELOAD_TOUCHED をだれかに発信


→データ保存してるコントローラ:RELOAD_TOUCHEDを受け取る

→保存されてるデータを再取得(更新)

→更新されたデータを発信 DATA_RELOADED


→ビュー:DATA_RELOADED を受け取ってデータ表示更新


とりあえず書いてモヤッとしてるところ


Scalaからだと、使うオブジェクトがextends必須

→Javaから書いたので残ってしまった超残念な部分。Akkanizeさせたときに消す。


コアがシングルトンなobject

→一番なんとかならんかなーって思った箇所で、Actorsのchannelとかをちゃんと使えば出来たような気がします。

次必ず消します。


ScalaScalaしてない

→ログの機構とかにListBuffer使いまくってます。吊ってきます。


キャストって言う動作が完全に終わってる

→Akka版作るときは型変換効かせたいです。


Javaから使うのを優先しすぎた感ある

→Javaでテストを書いていたので、書きにくい形式を選べませんでした吊ってきます。

次回からScalaオンリーの予定。


遅い

→Javaから使って、messageが同期で届くまでに0.01秒くらいかかってる感じ。

ボトルネックは、通信のたびに小さな内部Actorを作っている事。


Actorsの実装だと、Actorから自分自身を呼び出すとロックする。

それを回避するために、自分自身へのメッセージ送付を肩代わりするActorが一瞬だけ生成される。


例えば下記の、親を呼ぶメソッドからは、



def callParent(exec : String, message : Array[TagValue]) = {

log += Log.LOG_TYPE_CALLPARENT.toString

val future = parent(0).duplicate !! CallParent(exec, message)

val result = future()


result match {

case Done(_) =>

case Failure(reason) =>

}

}


duplicateメソッドでActorを一つ作って、ネストした際のロックを避けるようになっている。



def duplicate : SubMessengerActor = {

new SubMessengerActor(this, myself)

}



で、SubMessengerActorの実装は、まんまActor。


class SubMessengerActor(master : MessengerActor, myself : MessengerProtocol) extends Actor {

start


def act() = {

loop {

...



Actorの中に、通信のたびに別のActorが生まれて、終わったら消える。

こんなのがメッセージごとにあるので、めっちゃコスト喰うし、遅い。


Akkaだとネストしても平気なので、デフォで似たような機構が入ってるのかもしれないけど、最適化とかいろいろホラ。。


GCあるのに、Dealloc相当のメソッドがある

→Actorの都合上、停止は明示的に書かないといけないです。

このライブラリのMessengerも、

closeでMessengerだけを、

closeSystemで「系」全体を停止させます。


どうすればいいのかわかりません。GCさんよろしくお願いします、、よろ、、し、、、



今後

Akka化にあたって、サーバ間でのremoteをサポートして、remote間でのMessagingを簡単にする。


社内サービスで使うつもり。





ざっくり、以上。


それこんなライブラリ使うともっと簡単にできるよ、とか、

車輪の再発明乙、とかだったら切ないので教えてもらえるとたすかりんこ。


wrote 2012/10/16 0:07:08

EclipseScalaやる場合の注意点


概要

自分だけではなく、弊社の他の人も踏んだバグがちらちら重複してきた感があるので、

まとめてみた。


対象環境は、Scala IDE 2.0.2 + Eclipse 3.7.2 + Mac OS 10.8.2

ちなみに、どれも「完全再現できない」感じ。

時々発生する。


Eclipse+Java+Scala複合の問題


Javaで定義した定数の内容をScalaからは認識できないことがある

Java側のクラス情報の更新が、Scala側まで伝わらない模様。


たとえばJava側で

static final String a = "a";


とか書いてて、scala側から使用していると、

println(a)// "a"


Javaの方で定数の値を変更しても、

static final String a = "b";

Scala側で

println(a)// "a"

の、まま、という。


クリーニングは無意味。

Eclipseの再起動で直る。

気づきにくいのが一番辛い。



Eclipse+Scala単独の問題


object/classファイルを作成後、class/objectに切り替えると、ビルドエラーが出ることがある

Scalaプラグインを入れたEclipseのウィザードから、

object/classを作ったあと、内容編集でobject → class とかに編集すると、

ビルド時/実行時にエラーになる。

クリーニング効かない。

Eclipseの再起動で直る。


Scalaのコンストラクタの引数をあとから足すと、new演算子にエラー表記が出っぱなしになることがある

・Scalaのコンストラクト時の引数を、適当なタイミングで足すと、new演算子がエラー出す事が有る。



・newするコードが既にある

val a = new A("name")


状態で、Aのコンストラクタ引数を加えると、


class A (name : String) = {}

class A (name : String, value : String) = {}

val a = new A("name", "val")

newが、エラーを吐くようになる。

クリーニングも再起動も効かない。


エラーを起している行そのものを一度消して、書き直す(カット&ペースト可)

とかやると、エラーが消える。


エラーのデータが残ったままになってるっぽい。



メモまでに。


ちなみにScalaIDEの中に入ってるsbtとかは、プラグインのversion見ようとしたり、エラーが発生したりするとチラチラ見れる。

スクリーンショット 2012-10-15 23.11.35.png

wrote 2012/10/13 21:37:37

Specs2で嵌っていた話


概要

Scalaでマルチスレッド的なアプリケーションを作っていた。

テストしつつ。


で、今回はSpecs2を使ってるので、


"testCollection" should in {

"test1" in {

...

}


"test2" in {

...

}


"test3" in {

...

}

}


みたいに書いてた。



事象

あるテストを、バリエーション含めて3件書いていた時、

各テストの有無によって結果が変わる。

まーきっと自分たちのバグだろーと思ってまとめつつ、下記のようにケースを書き出した。


テストしていた対象は、

Actorを内包したクラスで、タイムアウトを指定/指定せず動作

・テストケースではwaitをかけて、起動→動作が終わったかなーっていう時間まで待つ→待機解いてチェック

ということを行っていた。



1 タイムアウト無し

2 タイムアウトあり時間内に終了

で問題が出る?→違った



1 タイムアウト無し

3 タイムアウトあり

で問題がでる?→違った



1 タイムアウト無し

2 タイムアウトあり時間内に終了

+

3 タイムアウトあり

で1,2がRunningで停まる(1,3だったり、2,3だったりランダムな事があとで判明する)



ただ単に時間がかかる系?違うな。必ず、ってのがおかしい。

内容について調べてみると、別インスタンスのはずの、各テストケースのクラス中のvarが更新されてしまう、というのが原因だった

なんでこんな事が?



最終的に

→Threadの止め方の問題だった。

Specs2は、非同期のテストを書きたい場合は、そのまま、


Thread.sleep(long) 


で、待てば良いのだった。


このへん、待つ機能を独自に作って使い回してたのが判明(Actor側に同期通信投げてActor内でThread.sleep)

穴を掘って穴に嵌った形。

値が同期したのは、単純に「システムの一部がロックして、値が変わらなかった」のを誤って観測したため。

お粗末!

wrote 2012/09/29 14:48:41

フロー記述のオレオレ形式作る


概要

・処理の並列分岐

・処理の合流/待機

・値の受け渡し

をとあるサーバからサーバ群に渡すために、1ラインで書ける記法が欲しかった。

で、探したけど良いのが無かった。


ので、作る話。

パーサの実装はScala。



対象

jar(内部でshellを制御するものもアリ)



記法

A>B,C,D(A:a:c)>E(D:d:e),F(A:a2:f, B:b:f2)<J,K>I(J:j:i)+D>G>H+G>J!Z


Aとかは、JSONで別途記述する、「プロセスオーダー」 いわゆる ジョブ の、

アイデンティティー。

プロセスオーダー Aがあるとき、それはshellとかjarとか通信とか、プロセスidを一つ持つような物事の単位とする。

JSONで表記する。


たとえばパラメータとしてAShell exec -key1 value1 -key2 value2 を受け取るshell AShell.shがあるとき、

{

"A":{

"type":"sh"

"class":"AShell.sh",

"exec":"exec",

"kv":{

"key1":"value1",

"key2":"value2"

}

}

}

解釈は→

AShell.sh exec -key1 value1 -key2 value2


typeがjarだったら、

java -jar Ashell.jar exec  -key1 value1 -key2 value2


この情報を基礎に動作する。

→タイプ一覧は下記


ワンライナーにJSONとして与えれば良い。


ex:

{"A": {"class": "AShell","exec": "exec","kv": {"key1": "value1","key2": "value2"}},"B": {"class": "AShell","exec": "exec","kv": {"key1": "value1","key2": "value2"}},"C": {"class": "AShell","exec": "exec","kv": {"key1": "value1","key2": "value2"}}}


引数として上書きする分だけ、プロセス間渡しとかを行う形。



記述規約:

・> で終了時次プロセスに移行

・(プロセスID:代入元パラメータ:代入先パラメータ) D(A:a:c) で、プロセスオーダーDについて、Aのパラメータaをキーcに代入して実行

・+ で分岐.+Dとあれば、プロセスオーダーDが終了したら開始される並列分岐

・< で特定プロセスの終了待ち。<J,KでプロセスJ、Kの完了待ちを行う

・, で内容のArray化。複数要素の並列稼働

解説:

1.AからB,C,D3つの並列、DでA値aをcパラメータとして使用、すべて終わったらEに収束、 D,Fを並列。D値dをeとして使用、FではA値a2をf、B値bをf2として使用。

完了したらJ、Kの完了が来るまで待機、

Jが着たら実行して処理終了。


2.D完了時、G,Kへとプロセス分離、H完了後終了。


3.G完了後、Jへとプロセス分離、J完了後終了。


4.J,K完了後、Iを実行。J値jをiとして使用。

5.途中で何があっても、プロセスZが最後に実行される(finally節)。


パース順:

! :Filnallyの取得/プロセスオーダー群としてのID配布、コンテキスト生成

+ :並列シーケンスの列挙 -> 各シーケンス化

> :シーケンスの内容分解、列挙 -> プロセス群化

< :プロセス群に対するwaitの解釈 -> プロセス群へのwaitのアタッチ

, :プロセス群のArray化

(:::) :プロセスに対する予約、パラメータのlazy用意 ここが一番大変そう。


こんなもんか。


プロセス自体の詳細は、

・importの記述

・インスタンスの記述

・アイデンティティからexec作って実行コードに配置


ProcessOrderのタイプ一覧

process:Mondogrosso互換のプロセス。com,kissaki.mondogrossoパッケージの継承物で、要はimportが可能。

jar:外部.jarファイル。

sh:外部shellファイル。


値のマトリクスは下記表



プロセス内の話

プロセスIDと、JSONから得た情報

キーとバリューがあるはず

どうやって入力したい?

←できるだけ可変できるように、かつ確認しやすいように

←DBに値で持つ

←ファイルで持つ

その場合、load方法を指定できれば良いのか。

→HTTP系までつくるのめんどうだから、Ver1.0系は、愚直にやろう。コピペで行けるし。






wrote 12/08/23 10:12:39

ストリームビューについて


概要

ストリームからビューを形成する技術について考えてみる


なぜストリームか

既存のHTTPだと、getで取ってきたものを表示する、となる。

これって、言い換えるとget単位でしかものを扱えない。

その事によって制限が生まれている。


例えば、変化に段階を持つ事になるのだが、それによるビューの変化が

DOMのせいでやりづらい。


DOMはあくまで一発での変更には強いのだけれど、連続した変化のためには、

細部の構造を逐一把握し、書き換える必要があるため、大規模なgetで得られるものとは相性が悪い。


このへん、ストリームが解決になるんではないか。



「ブラウン管」方式

CSSをばんばん送りつける。HTML構造によらずに画面を変化させる。

受け取った瞬間にトリガーオンで何もかも動かす。

常に動き続ける。アクションとかもその都度小さなものが送りつけられる。


ビュー順によるenabilityとかクライアントサイドで考えないで済むかも。


アニメーションも、streamでCSSの内容を変化させながら行う。

HTMLは通信基盤とかデータ層に使うかも。

JSは通信に使用する。

↑一度、手法について学んだ方が良さそう。

・ブラウン管など、旧来のテレビの手法

・地デジの手法

・Webでのストリーミングの手法、個人がStream出来る仕様なのか。



ストリームによって担保されるとうれしい事

・スケール

ユーザー一人一人が電波塔になってくれると、凄くうれしい。


・制御構造の簡素化

クライアントサイドでガチャガチャやる量を減らす。

もちろん消えないけど、定式化できるはず。



wrote 12/08/20 1:51:01

Specs2Gradleで使う


概要

Scalaのテストツール Specs2をGradleから使おうとした時に

つまづいたのでまとめまでに。



Specs2以外のテストツール、Scalatestだと解りやすかった

ScalatestをGradleから使う方法


Scalatestのユニットテストはこんな感じ。


import org.scalatest.FunSuite

class SampleTests extends FunSuite {
	test("Something") {
		val a = List("A", "B")
		val b = Seq("A", "B")
		assert(a == b)
	}
}


こいつを起動する事ができればOK

Gradleのtestタスクを上書きして、Scalatestを実行できれば良い。

例えばtestタスクをこんな感じにするとOK。


task test(overwrite: true, dependsOn: testClasses) << {
    ant.taskdef(name: 'scalatest',
        classname: 'org.scalatest.tools.ScalaTestAntTask',
        classpath: sourceSets.test.runtimeClasspath.asPath
    )
    ant.scalatest(runpath: 'build/classes/test',
        haltonfailure: 'true',
        fork: 'false') {reporter(type: 'stdout')}
}


タスク testClassesに依存する形で、

このタスクを実行するとまずtestClassesが実行されて、

次にantTaskとしてscalatestというのを定義、

そのままパスを与えて実行する。


インプットできるパラメータとかを明示してくれていて使いやすい。



で、Specs2

勝手が分かんなかったので、


死霊を見るに、

Specs2の死霊

http://etorreborre.github.com/specs2/guide/org.specs2.UserGuide.html#User+Guide

→Specification をextendsしたテストを書いて、タスク testで実行するようにすればよさげ。


試しに小さなテストを書いて、Gradleから実行してみる事にした。



build.gradle側記述

dependenciesに下記を記述


testCompile (
	[group: 'junit', name:'junit', version:'4.5'],
	[group: "org.specs2", name: "specs2_2.9.2", version:"1.12.1"],
	[group: 'org.specs2', name: 'specs2-scalaz-core_2.9.1',version:'6.0.1'],
)



テストクラスの内容は下記

package com.kissaki

import org.specs2.mutable._
import org.specs2.runner.JUnitRunner
import org.junit.runner.RunWith
 
@RunWith(classOf[JUnitRunner])
class SampleTests extends Specification {
	
	"Some test for my specs2 understand" should {
		"same-check between List & Seq" in {
			val a = List("A","B")
			val b = Seq("A","B")
			
			 a == b must beTrue
		}
	}
}


これらを整えた状態で、

gradle test


とやると、依存性解決してこんな感じになると思う。

スクリーンショット 2012-08-19 23.07.19.png

いつも通りGradleによるテストのreportsも作られてる。

スクリーンショット 2012-08-19 23.09.06.png

中身はこんな感じ。

スクリーンショット 2012-08-19 23.10.03.png


htmlを吐く機能が付いてるんだけど、どっちかって言うとGradleが吐く奴の方が

見た目にはすっきりしてて一次情報としてはうれしい感じ。



ここに嵌った

runner.RunWithインポートするの忘れてて、1時間くらい無駄にした。



サンプルプロジェクト

https://github.com/sassembla/ScalaSpecs2WithGradle


wrote 12/08/19 19:37:58

Gradleversionの上げ方


概要

1.0を使ってたんだけど1.1が出たので、上げがてら

簡単な上げ方を見てみる。


HomeBrewで入れたしHomeBrewでupgradeできませんかね

何も考えずにbrew upgrade gradle

Error: gradle-1.0 already installed


brew outdated

→なんもなし。


はい。

まだHomeBrewには1.1入ってないのね。

→12/08/08 22:36:43 まさに今さっき実行したら、Downloadが開始された。

わーい!



手段について調べる

次の2つが思いつく。

・普通に落として入れる

・gradlewでのversion指定効果を使う



普通に落としていれる

http://www.gradle.org/

から落として入れ替ry


gradlewでのversion指定効果を使う

「ぶっちゃけcacheに入ったりするんだろうか?」

という好奇心からやってみた。

結論から言うと、gradle1.1がcacheに入った。


まずbuild.gradleのWrapperのバージョンを書き換えて、


task wrapper(type: Wrapper) {

    gradleVersion = '1.1'

}


コマンドラインから、gradle wrapperを実行。

gradle wrapper


これで準備完了で、次回以降にgradlew を使ったタイミングで、勝手にversion1.1のGradleを取得してくる。


取得されたgradle 1.1は、

user以下の


.gradle/caches/


に入っている。

こんな感じ

スクリーンショット 2012-08-05 17.37.49.png

以降、gradlewを使った場合は、勝手に1.1が使われてくれる。

スクリーンショット 2012-08-05 17.54.20.png

自社だと、サーバ側はgradleではなくgradlewを使うようにしているので、

これでVersion Up が超簡単に済む事が解った。



wrote 12/08/05 17:03:02

argotを使ってコマンドラインツールを作ってみる


概要

Scalaのコマンドラインツール用parser 


argot

http://software.clapper.org/argot/


を使って、コマンドラインアプリケーションを作ってみる。

GNUっぽいコマンドライン

-p

--param

とかの短縮系を作れたり、


下記のような表記を勝手に生成してくれる。

スクリーンショット 2012-07-28 20.52.46.png

パラメータ、オプションについて、mustにしたりoptionalにしたりが簡単。

可変長なパラメータも取れる。


なによりScalaの型処理がいろいろ使えてまいうー。


Gradleの設定

このライブラリ自体が、同じ作者の別のライブラリに依存しているので、

解決しとく。


下記内容で、argot自体とargotが依存しているgrizzledっていうMathライブラリが解決できる。


compile (

[group: "org.clapper", name: "argot_2.9.2",version: "0.4"],

[group: "org.clapper", name: "grizzled-scala_2.9.0",version: "1.0.11.1"]

}



使用法想定

java -jar ツール.jar オプションとかパラメータ、みたいに使うのを想定する。



ライブラリ自体の簡単な利用方

1.argotをimportしとく

2.parserを定義

3.option引数とかを定義

4.parameter引数とかを定義

5.値を読む



1.argotをimportしとく

どうせ使うので、convertersもimport。


import org.clapper.argot._
import ArgotConverters._



2.parserを定義

importした上で、parserを定義する。

定義したaprserに文字列の配列を喰わせて使用する。


自分はそのまんまmain関数で使用するので、


def main(args : Array[String]) {
	val parser = new ArgotParser("MondogrossoFileObserver", preUsage = Some("Mondogrosso fileObserver"))
	//このへんにパラメータとかオプションとかの定義を足す
	parser.parse(args)
}


みたいなかんじ。



3.option引数とかを定義

例えば、ファイルを引数に取るオプションはこんな感じに定義できる


	val observe = parser.option[File](List("observe1"), "observe2", "Input files to read. If not specified, use stdin.") { (s, opt) =>
		val file = new File(s)
		if (!file.exists)
			parser.usage("Input file \"" + s + "\" does not exist.")
	
		file
	}



4.parameter引数とかを定義

文字列を読むような引数の場合、


	val req = parser.parameter[String]("foo", "some param", optional=false) {(s, opt) =>
		s
	}


optionalのtrue/falseで、必須かどうかが設定できる。



5.値を読む

当然だけど、parse後、読み込んだ値を使う事が出来る。

	parser.parse(args)
	println("find	" + find.value)


肝心な使い方

一応書いておくと、

java- jar ファイル名.jar -オプション opt パラメータ



やってみた系(actorとかも使っててごちゃごちゃしてるけど)

https://github.com/sassembla/MondogrossoFileObserver

wrote 12/07/28 18:09:47

Gradleの機能を使って、GithubMavenRepo


概要

Gradleで管理しているプロジェクトを、Github上にupして、

MavenRepoとして使用できるようにする。

以降は、MavenCentralに代わって、自分たちのGithubを依存性解決に使えるようになる。


(private useのための認証などは書いてません。すまん、眠い。)



おおざっぱな手順

1.build.gradleに追記、MavenRepoとしての設定を書きこんで、MavenRepo用にビルド。

2.ビルドしたものをGithubにpush。

3.使用するプロジェクトを一つ作る。

4.2でupしたMavenRepoに依存する感じに設定してウマー



こちらが出来上がったものになります

既存のいい感じのが無いので新規で用意。実際に作ったものを下記にupしておいた。

MavenRepoになる側

SampleMavenRepoByGradle

https://github.com/sassembla/SampleMavenRepoByGradle

Github上のMavenRepoを使う側

SampleGithubRepoUseProjectByGradle

https://github.com/sassembla/SampleGithubRepoUseProjectByGradle



1.build.gradleに追記、MavenRepoとしての設定を書きこんで、MavenRepo用にビルド

通常のJavaプロジェクトをビルドする以外に、下記の部分がMavenRepoを作る上でポイントになる。


//MavenRepository identity setting リポジトリの設定。これらは当然、読み込み時に使用する
group = 'com.kissaki.sample'	//グループ
archivesBaseName = 'Samplemavenrepobygradle' 	//アーカイブベース
version = '0.0.1'		//バージョン

uploadArchives {//アーカイブに際して、Maven形式で、どこに出力するかを指定する箇所
	repositories {
		mavenDeployer {
			repository(url: "file:${projectDir}")
		}
	}
}

//まんまコピペさせてもらった、pomのライセンス情報とかを設定する箇所
[install.repositories.mavenInstaller, uploadArchives.repositories.mavenDeployer]*.pom*.whenConfigured { pom ->
	pom.project {
		inceptionYear '2012'
		packaging 'jar'
		licenses {
			license {
				name 'The Apache Software License, Version 2.0'
				url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
				distribution 'repo'
			}
		}
	}
}


この状態で、src下に下記ファイルがあるとする。

src/com/kissaki/sample/

SampleMavenRepoByGradle.java


内容は

package com.kissaki.sample;

public class SampleMavenRepoByGradle {
	public void something() {
		System.out.println("Something!!");
	}
}


この状態で、


gradle uploadArchives

ってやると、

com/フォルダ以下がちょこちょこ作られる。(凄く横に長い画像)

スクリーンショット 2012-07-26 23.58.23.png

中身にはjarとかpomとかが出来てる。pom、、、なんて汚らわしい。



2.ビルドしたものをGithubにpush

まんま、Githubにpush。

comなんちゃらも、ちゃんとaddして含もう。



3.使用するプロジェクトを一つ作る

SampleGithubRepoUseProjectByGradle を作成。


Javaのプロジェクトで、せっかくなのでmain関数の中で

SampleMavenRepoByGradle.java の内容を使う。


src/com/kissaki フォルダ以下に下記を用意。

SampleGithubRepoUseProjectByGradle.java


package com.kissaki;

import com.kissaki.sample.*;

public class SampleGithubRepoUseProjectByGradle {


	/**
	 * @param args
	 */
	public static void main(String[] args) {
		SampleMavenRepoByGradle m = new SampleMavenRepoByGradle();
		m.something();
	}

}


この状態で gradle compileJava とかやっても、SampleMavenRepoByGradleクラスの依存性解決ができず

エラーになること必須。



4. 2でupしたMavenRepoに依存する感じに設定してウマー

githubへの依存は、こんな感じに書けば良い。


repositories { 
	mavenRepo urls: 'https://github.com/sassembla/SampleMavenRepoByGradle/raw/master/'
} 
 
dependencies {
	compile 'com.kissaki.sample:Samplemavenrepobygradle:0.0.1'
}


repoについては、Web上のgithubリポジトリのアドレスに、raw/master をつけてあげる事でOK。

compile時に依存するので、依存内容であるMavenRepoのidentityを書く。


で、実際に、 gradle compileJava でビルドしてみると

スクリーンショット 2012-07-27 0.25.27.png

あら、一発でうまく行った。(写真はTextMateのGradle bundle を使っています)

せっかくなので、jarで動かせるように、下記をbuild.gradleに書き加える。

jar {
	manifest {
		attributes 'Main-class': 'com.kissaki.SampleGithubRepoUseProjectByGradle' 
	}
	
	from {
		configurations.runtime.collect {
			if (it.isDirectory()){
				it
			} else {
				zipTree(it)
			}
		}
	}
}


からの、

gradle jar

スクリーンショット 2012-07-27 0.28.42.png

できたー。

実行してみよう。


java -jar /Users/sassembla/Desktop/SampleGithubRepoUseProjectByGradle/build/libs/SampleGithubRepoUseProjectByGradle.jar

スクリーンショット 2012-07-27 0.30.30.png

パーフェクトだウォルター。



参考

krmdから、この辺を参考にしたって聞いて自分も参考にしました。

http://wadahiro.hatenablog.com/entry/2012/07/24/234727

http://downright-amazed.blogspot.jp/2011/09/hosting-maven-repository-on-github-for.html

wrote 12/07/26 23:19:43

JSXHaxeGWTそれぞれのJavaScriptの使い方


概要

JavaScriptみたいなダメ言語触ってちゃダメです。

もうちょい高度な事を簡単にできるように、変換系の言語使いましょう。


っていうなかで、JSXとHaxeとGWTそれぞれを、弊社内でぶつくさ言いながら触ってみてる

2人で愚痴りながら、それぞれの違いとか特質とか書いてみてる。


重点として、global namespace pollutionと戦えるかどうか、というのが注目すべき点になります。



JSX

http://d.hatena.ne.jp/nishiohirokazu/20120531/1338456208

を参考に。

var jQuery = js.global["$"] as function(:string):variant;


これって、

既にブラウザに読み込んでるjQueryを読み込むって事になってる。

名前空間は、、?

・JSの読み込み方そのまま、<Script>タグで読み込まれている必要がある

・JSを文字列を介して読み出すことが出来る

・JSをオブジェクトとしてJSX内に初期化する方法自体は無い(パッケージラッピングなどが出来ない)

ので、global namespace pollutionと戦えない。

この辺は、ネットワークかフォルダから読む方法が無いと、話にならんぞ。

きっとあるんでしょう。、、、みつけらんないんだけど。



Haxe

http://blog.romatica.com/2012/01/09/haxe_jquery/

を参考に。

って調べてみたら、やたらとHaxeラッピングされているJavaScriptライブラリが多い。

jQuery、ProcessingJS、linq、、、linq!!? (二度見

http://gitorious.org/more

資産多いねー。

で、肝心のHaxeでjQuery、上記ライブラリの中身を追う事で調べてみ


調べてみ、、、てるとこ!! 読み方何通りもあるわこれ。

・コンパイル時に組み込んでしまう事で、global namespace pollutionと戦える。

http://stackoverflow.com/questions/3828423/haxe-for-javascript-without-global-namespace-pollution

・<script>タグからの読み込みも可能

・ライブラリを介してのオブジェクトとしてのJS読み込みが可能(書き途中



GWT

オワコンなので特に語る必要は無いが、一応。


・<script>タグからの読み込みが可能

・JSNIがあるので、JavaとJSのあいだを型をつかったまま行ったり来たりできる。

JSNI内でjsを読み込む事で、global namespace pollutionと戦える。

・GWT独自のJS読み込みスロットあり。Script読み込みを書く場所が限定される。

・JSに対して、Java由来のガッチガチの名前空間パッケージラッピングが可能

static,public,private final ほか



雑なまとめ

JSの読み込み方一つで、いろんなバリエーションがあるんですね!

個人的には名前空間に配慮できるものをきちんと使うのが、クソJSをマジックハンド介してとはいえ

触る上での、最低限ジェントルマン的な嗜みかなーと思います。



参考(にしてる途中の何か)

Haxe、2012/5時点でのFlashDevelopとの連携まとめ

http://robertbak.com/wordpress/2012/05/getting-started-with-haxe-for-javascript/


Haxe、JSからの値取得、xml読み込み

http://www.youtube.com/watch?v=KlJ4VSifpsY


Haxe、っていうかFlashとかとも連携できる(4年前、、、!!)

http://trac.puremvc.org/Demo_Haxe_JS_Flash_MultiplatformComm


Haxe、incrootっていう修飾子でjs読み込めるcompilerっぽいの。

http://code.google.com/p/haxetacy/wiki/postcompiler


Haxeの資産すげーーーーー。。

wrote 12/07/26 2:16:04

Akka Remoteを試す


概要

akkaのサンプルを落としてきて、remoteActorについて学ぶ。


解説用サンプル

https://github.com/sassembla/ScalaAkkaRemoteActorWithGradle



準備

サンプルならそのまま動く。


以下は、自分で環境から用意しようぜ、的な話。



まずはakkaをゲットしよう。


おぞましい事になる。

git clone git://github.com/akka/akka.git

で、手元にakkaが落ちてくる

重い

とっても重い


しかも70%超えたあたりから胸をしめつけるような重さ

重い



sbtでプロジェクトを走らせる

都合、2以上のプロジェクトを走らせる必要がある。

ひとつひとつをターミナルで実行する。



まずは一つ目、CalcApp

akkaのフォルダで、

env JAVA_OPTS="-Xmx2048m" sbt

予めPermGen space 1Gで確保しとく。

これがまたえらい時間がかかる。


なんか一段落着いたら、

akka >

が表示されて止まると思う。


試したい該当のプロジェクトは、


akka/akka-samples/akka-sample-remote


なので、

project akka-sample-remote


で該当プロジェクトを定めて、

run



落としたそのまま実行しようとすると、

Multiple main classes detected, select one to run:


 [1] sample.remote.calculator.CalcApp
 [2] sample.remote.calculator.CreationApp
 [3] sample.remote.calculator.LookupApp


とか聞いてくる。

README読むと解るけど、3つアプリが入ってる。

最初は1 CalcApp を選択。

Enter number: 1


Started Calculator Application - waiting for messages

とか帰ってくるので、この状態で放置。



次に、LookupApp

別のターミナルを

akkaのフォルダで立ち上げ、

同じ手順で、3を選ぶ。

Enter number: 3


同じ手順で、3を選ぶ。


するとこうなるterminals.png

左が1 CalcApp 

右が3 LookupApp

2つのTerminalが連動しているのが解ると思う。


(右 LookupAppが計算問題を出し、)

左 CalcAppが計算問題に答え、

右 LookupAppが受け取った結果を表示

という事をしている。

通信はすべてActorを通して、サーバはNettyが使用されている。



内容解説

ここまでのセットアップ後、最小範囲での依存解決とかをして、

あとで自分が忘れても解りやすいようにしたものを、Gradleでビルドしておいた。


https://github.com/sassembla/ScalaAkkaRemoteActorWithGradle

(この記事トップのものと同じ)


①CalcApp側.1

Actorを起動して、放置。

RemoteActorの通信が来るのを待ち受ける。


class CalculatorApplication extends Bootable {
	//#setup
	val system = ActorSystem("CalculatorApplication", ConfigFactory.load.getConfig("calculator"))


このコンフィグがキモで、

resources/ 下の conf ファイルがそれ。

application.conf から一部抜粋すると、


//#calculator
calculator {
  include "common"
	  include "reference"
	
  akka {
    remote.netty.max-total-memory-size = 0b
    remote.netty.max-channel-memory-size = 0b
    remote.netty.execution-pool-size = 4
    remote.netty.execution-pool-keepalive = 60s
    remote.netty.backlog = 4096
    remote.netty.connection-timeout = 120s
    remote.netty.outbound-local-address = "auto"
    remote.netty.message-frame-size = 1 MiB
    remote.netty.reconnect-delay = 5s
    remote.netty.all-timeout = 0s
    remote.netty.write-timeout = 0s
    remote.netty.read-timeout = 0s
    remote.netty.reconnection-time-window = 600s
    remote.netty.backoff-timeout = 0ms
    remote.netty.secure-cookie = ""
    remote.netty.require-cookie = off
    remote.netty.use-passive-connections = on
    remote.backoff-timeout = 0ms
    remote.untrusted-mode = off
    remote.remote-daemon-ack-timeout = 30s
    remote.transport = "akka.remote.netty.NettyRemoteTransport"
    remote.log-received-messages = on
    remote.log-sent-messages = on
    remote.netty.port = 2552
  }
}
//#calculator


と、remoteCreationに関する設定


//#remotecreation
remotecreation {
  include "common"

  akka {
    actor {
      deployment {
        /advancedCalculator {
          remote = "akka://CalculatorApplication@127.0.0.1:2552"
        }
      }
    }
    remote.netty.max-total-memory-size = 0b
    remote.netty.max-channel-memory-size = 0b
    remote.netty.execution-pool-size = 4
    remote.netty.execution-pool-keepalive = 60s
    remote.netty.backlog = 4096
    remote.netty.connection-timeout = 120s
    remote.netty.outbound-local-address = "auto"
    remote.netty.message-frame-size = 1 MiB
    remote.netty.reconnect-delay = 5s
    remote.netty.all-timeout = 0s
    remote.netty.write-timeout = 0s
    remote.netty.read-timeout = 0s
    remote.netty.reconnection-time-window = 600s
    remote.netty.backoff-timeout = 0ms
    remote.netty.secure-cookie = ""
    remote.netty.require-cookie = off
    remote.netty.use-passive-connections = on
    remote.untrusted-mode = off
    remote.remote-daemon-ack-timeout = 30s
    remote.log-received-messages = on
    remote.log-sent-messages = on
    remote.transport = "akka.remote.netty.NettyRemoteTransport"
    remote.netty.port = 2554
  }
}
//#remotecreation


で、hostNameの設定だけは common.conf に出してある。


ひとまず起動すると、このサーバは単純に「待つ」。



②LookupApp側.1

Actor立ち上げ後、下記コード部分でActorSystemへの参加と、すでに起動しているCalcAppのActorの呼び出しをしている。


class LookupApplication extends Bootable {
	//#setup
	val system = ActorSystem("LookupApplication", ConfigFactory.load.getConfig("remotelookup"))
	val actor = system.actorOf(Props[LookupActor], "lookupActor")
	val remoteActor = system.actorFor("akka://CalculatorApplication@127.0.0.1:2552/user/simpleCalculator")


ローカルの2552ポートへとアクセス、名前(CalculatorApplication)とクラス情報(/user/simpleCalculato)でもって、CalcAppの呼び出しを発生させる。

ここで、2554ポートを使うと、remoteCreationが発生すると思う。今回のCalcAppははじめからActor込みで待ってるけど。


で、LookupApp は起動後、下記コードで

while (true) {
	if (Random.nextInt(100) % 2 == 0) app.doSomething(Add(Random.nextInt(100), Random.nextInt(100)))
	else app.doSomething(Subtract(Random.nextInt(100), Random.nextInt(100)))


	Thread.sleep(200)
}


定期的にappのdoSomethingメソッドを、ランダムな数値を2つ入れて実行。

doSomethingメソッドは、


def doSomething(op: MathOp) = {
	actor ! (remoteActor, op)
 }


な感じで、remoteActorに対して、actor経由でop(足したり引いたりとかのオペランドが入ってる型のオブジェクト)を

送りつける。

ここからはCalcApp側が受けるはなし



③CalcApp側.2

receive周りはこんな感じ


class SimpleCalculatorActor extends Actor {
	def receive = {
		case Add(n1, n2) 
			println("Calculating %d + %d".format(n1, n2))
			sender ! AddResult(n1, n2, n1 + n2)
		case Subtract(n1, n2) 
			println("Calculating %d - %d".format(n1, n2))
			sender ! SubtractResult(n1, n2, n1 - n2)
	}
}


Addがきたら、足してsenderに返す。とかしてる。

sender = LookupAppなので、返ると、、、



④LookupApp側.2

こちらのreceiverは


class LookupActor extends Actor {
	def receive = {
		case (actor: ActorRef, op: MathOp)  actor ! op
		case result: MathResult  result match {
			case AddResult(n1, n2, r)       println("Add result: %d + %d = %d".format(n1, n2, r))
			case SubtractResult(n1, n2, r)  println("Sub result: %d - %d = %d".format(n1, n2, r))
		}
	}
}


で、数式の結果(AddResult or SubtractResult)がきたら、プリントしてる。


という感じ。


wrote 12/07/21 19:03:10

GradleScalaプロジェクトをビルドする的な


概要

build.gradleでScalaのプログラムをビルドするってのを

ちゃんと小さくまとめてなかったので小さくまとめる。



フォルダ構成

本当はGradle標準にあわせたいんだけど、

万が一的な意味でEclipseで触ったりすることを考えてこんな形にしちゃう。

スクリーンショット 2012-07-15 21.46.51.png

フォルダ階層をEclipseのデフォルトに合わせる。

この時点でsrc、testフォルダは空。build.gradleは白紙。



なにはともあれWrapper

自分はTextMate x Gradleな感じなので、

TextMateのGradleプラグイン使うためにまずgradleWrapperを作ってしまう。

以下はずっとbuild.gradleファイルに追記。


apply plugin:"scala"


version = 1.0


task wrapper(type: Wrapper) {
    gradleVersion = version
}

この状態で、gradle wrapper をTerminalとかでやると、

gradlew.shとかexeが作られて、Gradle入ってない人でも楽に拉致できるようになる。

スクリーンショット 2012-07-15 21.52.43.png

終わると、フォルダがこんな感じになってる。

スクリーンショット 2012-07-15 21.54.34.png



srcフォルダの場所を書く

srcフォルダの場所とtestフォルダの場所が、通常のGradleとは違っているので、

書き加える。

sourceSets {
	main {
		scala {
			srcDir 'src'
    		}
	}
	test {
		scala {
			srcDir 'test'
    		}
  	}
}



Dependenciesを書き加える

Scalaのビルドを通すために、依存を書く。

repositories {
	mavenCentral()
}


dependencies {
	scalaTools  (
		[group: "org.scala-lang", name: "scala-compiler",version: "2.9.2"],
		[group: "org.scala-lang", name: "scala-library",version: "2.9.2"]
	)
	
	compile (
		[group: "org.scala-lang", name: "scala-library",version: "2.9.2"]
	)
}


これで、Scalaのコードをsrc内とかtest内に書けば、ビルドできる。



ビルド対象のHello.scala書く

srcフォルダ下にファイル追加

スクリーンショット 2012-07-15 22.02.45.png

Hello.scala

object Hello {
	def main(args: Array[String]) {
		println("necomimi-mode--!!!")
	}
}

趣向が凝らされた至高の文章。


このときのbuild.gradleの全体像

スクリーンショット 2012-07-15 22.07.43.png

わざわざ { } 使って書くこと無いけど、今回は時間ないし眠いので。



コンパイル

Terminalから、 

gradle compileScala


ってやっても良いし、TextMateから

+shift+G
compileScala


ってやってもいい。


Terminalからだと、

スクリーンショット 2012-07-15 22.11.17.png


TextMateからだと、

スクリーンショット 2012-07-15 22.07.33.png

こんな風に表示される。

(実際先にTextMateのほう動かしてしまったのでTerminalの方はもう最新でした的な表示が出てる)


buildフォルダが作られて、classとか出来てる。

testフォルダにテストとか書けば、gradle test から実行できる。



プロジェクト一式

https://github.com/sassembla/SampleScalaGradle

書いてる間に渋谷から横浜に着いた!



駆動方法

cloneしてから、Terminal で、

gradlew compileScala

とかすると、ネットにつながっててJavaが動きさえすれば、動くと思う。

wrote 12/07/15 21:44:52

Scalaをインストール + 実行可能環境をTextMateで作る


概要

まんま。



ScalaのInstall

何も考えずbrew install scala (事前にbrew search scala くらいはしておこう)

スクリーンショット 2012-07-01 13.17.41.png

スクリーンショット 2012-07-01 13.17.28.png

ok。



TextMateの設定

https://github.com/mads379/scala.tmbundle/


Cloneして、出来た.tmbundleを実行。

スクリーンショット 2012-07-01 12.42.34.png



設定をひとつ。

TextMateからScalaをコンパイルしたりスクリプトとして実行したりできる。


そのために、SCALA_HOME パラメータをTextMateに設定する。

環境設定 > Advanced > Shell Valiables

スクリーンショット 2012-07-01 14.10.00.png

スクリーンショット 2012-07-01 13.29.18.png

に、SCALA_HOMEを足す。

Scalaをhomebrewでインストールしている場合、/usr/local でOK。

スクリーンショット 2012-07-01 14.08.31.png

この状態で、TextMateでScalaのコードを書くと、

⌘ + r からいろいろ出来て素敵。


スクリーンショット 2012-07-01 14.19.35.png

とか

スクリーンショット 2012-07-01 14.20.29.png

とか。


実行結果。


スクリーンショット 2012-07-01 14.20.31.png

便利。


wrote 12/07/01 12:31:46

GradleでNettyサーバ立ち上げる


概要

ちょっとしたイベントサーバが欲しかったので、Nettyで遊ぶ。

いやーこれ良いオモチャだわ。



参考になる死霊

サンプル満載

https://www.jboss.org/netty/documentation

ものすごい充実っぷり


APIとか

http://docs.jboss.org/netty/3.2/api/index.html



青果物(誤字ったけどもうこれでいいや

https://github.com/sassembla/NettyEchoWithGradle



解説

単純にserveして終了時に画面に「最後に来てたinputのログを吐く」サービスです。

ただのひな形。



src下にある2つのファイル

EchoServer.java

EchoServerHandler.java

と、dependencyとして

netty 3.5.1.Final.java

てだけで動きます。

素敵。楽。

これだけでJava.nioが使えるだなんて。

ぶっちゃけドキュメンテーションからEchoServerをパクってきただけです。


動かし方とかは、clone後


gradlew jar

でjar作成


gradlew runJar

でjar実行。


portは8000番に固定してあります。

wrote 12/06/29 21:58:14

ネタ)ChromeをAndroid2.3系にインストール or DIEするサービス


概要

Nativeで入ってるブラウザがクソなので。

Webサービスとしてブラウザ置き換えちゃうサービスでどんどん駆逐してほしいです。

使い勝手が変わる? デフォルトがゴミだから耐えられるだろ?


Chromeanonymousをかけて、

Chromymousで。

ということでそういうサービスを考えてみました。



原因

Androidのバージョン交代は緩やかです。

現在配布されてるものが「ステキ!! 抱いて!!」的だったら良かったんですが

でもクソいブラウザが赦されてる2.x系はまだまだ2年は安泰っぽい。

なのでChrome for 2.3でこれらを駆逐しましょう。


ただ、ちょっとここで考えます。

単にChrome2.3出来たよーっていってもつまらないので


いっそ面白おかしく

クソブラウザを消去する課程をサービス化

したいところ。


他の事する布石にもなりますし。



遷移

端末からWebサイトにアクセス。


インストールしますか

y/n Tw認証とかFb認証。


y>対応端末(*1)ならインスト、ソレ以外なら「ごめん、だめだった。爆破していい?」>y/n


インスト時に「これから爆速ブラウザになるぜ!」とtw

n>「了解です。ところで爆破していい?」>y/n


爆破y x N(ホントに良いんですね?知りませんよ) > ☆



(*1) : 徐々に、生かしたい端末だけになるようにする。12/06/29 現在、勘で決めた対応端末条件は下記

・2.3系であること

・次の機種のいづれかであること galaxy, xperia, htc

・1年以内に発売された端末である事



目標

これでクソブラウザを☆にする。


クソブラウザしか使えない、対応外の端末で持ち主が同意した場合は端末ごと☆にする。


だんだんと消去の「ホントに?」の回数を減らす。死んでほしい端末ごとに減らす。


同時に対応してる端末もってるメーカやショップに連絡→端末供給する。クーポン化したい。


個人でも、自分のサーバにデプロイできるようにしたい。


利益は「クソブラウザおよびクソ端末の死」なので、既に十分受け取っている。一切の供与を受けない。無料。


そのうち、クソOSの死、に繋げられるはず。



ちょっとだけ冗談です。

wrote 12/06/29 15:49:52

テストを書かないと禁則事項的にダメなのでHaskellでもテスト書く


概要

イテレーション早くなるのでテスト書きたい。

ので、勉強。

HUnitについてのLTが


第一回スタートHaskell2 

http://atnd.org/events/29448

#start_haskell

で有ったので、行ってきた。



Haskellのテスト

発表者の @shokos さんのgithubを参考にしてる。

https://github.com/shokos/Haskell_test_tut


HUnit

Haskell Platformには入ってないので、自分でインストールしてね!

Haskell Platform使ってHaskell入れてる場合、


cabal

package system for Haskell software.

http://www.haskell.org/cabal/

http://www.haskell.org/cabal/users-guide/


が入ってるので、下記コマンドでインストールできる。


cabal install HUnit

スクリーンショット 2012-06-24 20.40.36.png

で、おわったら

自分はTextMate使ってるので、

サンプルにあげてくれてるファイルの中身をマルコピして実行してみる。

スクリーンショット 2012-06-24 21.33.09.png

実行結果

スクリーンショット 2012-06-24 21.32.58.png

OK。これは使いやすい。



QuickCheck

プログラムの特性をテストしてくれるツール。


こちらもcabalからinstall可能。

cabal install QuickCheck


スクリーンショット 2012-06-24 20.42.54.png

で、案の定コピペ。

ただし、こいつにはmain書かれてないので書き足し。

スクリーンショット 2012-06-24 21.46.38.png

実行結果

スクリーンショット 2012-06-24 21.46.35.png

99までテストされてて、ラスト付近は

スクリーンショット 2012-06-24 21.47.55.png

となっている。

べんりーーーーーーー!!!!!



勉強になった!!!

やっぱやったこと無い言語はいいのう。




どうでもいいことだけど

今日俺の性善説が死んだ。惜しいやつを無くした。

wrote 12/06/24 17:39:47

TextMateのOutline View でQuickLookが効くようにする


概要

この部分でQuickLookが効くと何かとうれしい。

スクリーンショット 2012-06-19 2.19.31.png

けいくんが何か知らないがSublimeText2でやりたいと言ってたので

そういえばTextMateとSublimeはプラグイン互換性有るなーと思って探してみたら


あった。

結局Sublimeで動くかどうかは試してない。

動くんじゃねーの。



DL

project一式

https://github.com/belkadan/textmate-quicklook

TextMate Bundle

https://github.com/downloads/belkadan/textmate-quicklook/TMQuickLook.tmplugin.zip



実行すると

quicklook.png

Outlone Viewで項目に対してSpace。



おまけ

ココから下は寝落ちしてる間にねこが書きました

xっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっっds

wrote 12/06/19 2:24:55

Javaでローカルの変数名を取得する


概要

Javaのプログラム中、

String a = なにやら;
log(a.name()+"="+a);


と書いて、

関数logから出力されるのが、


a:なにやら

とかなると、後から追うときちょっと楽かなと思った。

具体的には、記述として


String val1 = "val1Value";
String val2 = "val2Value";
System.out.println("val1="+ val1+"val2"+ val2);


ってのが

String val1 = "val1Value";
String val2 = "val2Value";
System.out.println(val1.name()+"="+ val1+val2.name()+"="+ val2);


になる。

特にリファクタリングが楽そう

もちろんStringクラスにフィールド名吐くnameメソッドなど無い。

(C#だとnameプロパティ有るけどねwww って教えてくれたobhrありがとう。ムカつく。)



方法's

コンパイラにオプション渡してそれっぽい情報がclassに乗るようにする+リフレクション

@tan_go238さん、@backpaper0 さん、@kimukou2628さん、@kurobaraさん、より

不明.pngbackpaper0 @tan_go238 @toru_inoue -gか-g:varsつけてjavacしないとローカル変数名や引数名って消えちゃう気が。フィールド名は普通に取れるけど。12/06/17 17:31



Javassistを使う

@masanobuimai さんより

1__#$!@%!#__不明.png

masanobuimai

@toru_inoue javassist使うとできるみたいですよ。http://t.co/lt4GcxGx

12/06/17 17:48



Paranamerを使う

@esmasui さんより。

1__#$!@%!#__1__#$!@%!#__不明.png

esmasui

@toru_inoue  paranamer使うといいと思いますの

12/06/17 18:14


これか。

http://paranamer.codehaus.org/

使用例は

http://d.hatena.ne.jp/Kazzz/20100222/p1



感想:Twitterすごい。

今回は用途が[できなくてはいけない]というレベルではないため、さすがにJavasstとかは

つかえないが、、

勉強になった。

で、



ここからうらがみさん無双

2__#$!@%!#__不明.png

backpaper0

@tan_go238 @toru_inoue やっとできたhttps://t.co/VOT8i5og

12/06/17 18:26


ふえー。できるもんなんだ、、 うらがみさんすげー、、!


手元で確認した範囲だと、


attr.getConstPool().getUtf8Info(attr.nameIndex(1));


はnameIndex(0)でthis, 1でaを返してくる。


言語仕様的に、採番は定義順っぽいんだけど(自分が、それ以外の方法でJVMが値マッピングの方法をとっている、という部分を見つけられなかったため確証は無い)


どうしても心配なら、順は保証されてないことにして、値の集合として扱えばいいと思う。

そういうふうにClassから切れば、つかえる。


1宣言のために1クラスだととっても効率悪いけど、1集合とかなら行けそう。



突然の話題に返答ありがとう!

重ねてお礼申し上げます。


神様、見てたらうらがみさんに日曜日をもう一日。

wrote 12/06/17 18:20:58

123Dカレーパーリー in ぬる舗


概要

Autodesk社の写真から3Dモデルを起すツール

123Dに興味があったりする人がぬる舗に集まって

@tan_go238 のカレーに舌鼓をうちながら

その場を3D化したりしていました。


タンドリーチキン美味しい。



123Dとは

これ。

http://www.123dapp.com/


の、特に今回はこちらを使用。

iPad(要iOS5.0)用アプリ

http://www.123dapp.com/catch


ぬる舗カレーパーリー現場を123Dで3D化

まず、カレーを用意したテーブルをiPad + 123DCatch for iPad で激写。



待つこと3分ほどで、123D上でのパーリーごたつ on Windowsスレート上の123Dアプリケーション。この時点で神々しい。

IMG_0451.JPG

ポリゴン境界を表示

IMG_0452.JPG


モデルを123Dからobj形式で出力してBlenderに入れてみたところ。

AvRfTGuCMAEL4G4.jpg-large.jpeg


Blenderから、SketchFabというWebGLでモデルを表示するサービスで公開。

http://sketchfab.com/show/eBRTjD5avKL4XnZLmoiTuIneXdc *要WebGL

fab1.png



まわすこともできる!

fab2.png


@neko_manma1 さんが公開に使ったサービス、SketchFabはこちら。

http://sketchfab.com/

Blenderのプラグインが公開されており、

@neko_manma1 さんがあっというまにぬる舗モデルをupしていた。



もう一丁

@mouri45 さんが持参してたスライムナイトのフィギュアを123Dでいじることに。


こたつに持参のろくろをセットして、スライムナイトが乗った箱を浮かせつつiPadを固定してまわしながら撮影。

まわるのはiPad側。

IMG_0461.jpg


123Dで表示したところ。

IMG_0462.jpg



wrote 12/06/13 23:57:21

MBAでMateDotとTermHereが動かない問題


概要

Finderに置ける、TextMateとかTerminalのショートカットアプリケーション。

http://manas.tungare.name/software/finder-apps/

スクリーンショット 2012-06-13 12.21.09.png


次の3種類が有る。

TermHere Terminal.appをそのフォルダにcdした状態で開く

MateDot TextMateをそのフォルダについて開く

Touch 新規ファイル作成



困ったこと

MBAの新型(2012Mid)使うようになって、

「アイコンをクリックしても動作しない」と直面。


この問題は、2ヶ月くらい前に同僚が発症してた。

あのとき解決しておけば良かったなあ。。。


ということで、、解決しよう。



原因

アプリケーションの実行自体が、TermHere.app内部のshellまで到達してない模様。

.app内部のshellを直に実行したら動いた。


ので、

スクリーンショット 2012-06-14 21.37.47.png

から、Contents > Resources > Scripts と進んで、

スクリーンショット 2012-06-14 21.37.55.png

心臓部のスクリプトをAppleScript エディタ で開く。

スクリーンショット 2012-06-14 21.38.05.png

開いたら、別名保存 > 名前を、TermHereならTermHere.app に変えて、アプリケーションとして保存。

下記はTouchなのでTouch.appにする。

スクリーンショット 2012-06-14 21.38.33.png

するとこんな感じになるはず。 

スクリーンショット 2012-06-14 21.38.44.png

これで、アプリケーションとしては、動作するようになる

けどアイコンがScriptのものになってしまう。

名前も、表示されなくなる。


ここで、一つ上の階層のapplet.icnsを⌘+cでコピーしておいて、Touch.appを もう一度右クリック > パッケージの内容を表示、と進んで、、

1__#$!@%!#__スクリーンショット 2012-06-14 21.37.47.png

中に入ってる.icnsに先ほどコピった.icnsファイルを上書きすると、Touch.appのアイコンがかわる。

スクリーンショット 2012-06-14 22.00.14.png


これを、ファインダーにD&Dすれば、完了。


名前消えたけど。入れ子になっちゃったけど。

動くからいいよね、、、

wrote 12/06/13 12:22:54

Macでプレゼンとかで画面の特定の箇所をズーム


概要

Macで、プレゼンとかするときに、画面の一部をズームしたくなるときがあります。

最初からそういう機能があるので、紹介。


設定

環境設定 > ユニバーサルアクセス > 視覚 > オプションスクリーンショット 2012-06-13 0.47.01.png

スクロールホイールと修飾キーを使ってズーム の項目にチェックが付いてたら、そこに入力してある

修飾キーを押しながら、 + タッチパッドだったら上下2本指スワイプ、マウスだったらホイール回すと、

スクリーンショット 2011-07-30 15.25.33.png

現在カーソルが置いてある場所を中心にズームインします。

自分は⌘を左指で押しながら上下2本指スワイプがやりやすいので、変えてます。



wrote 12/06/13 0:46:20

RailsInstaller使ってみた


概要

Mac、こういうマシンで試した。

スクリーンショット 2012-06-12 19.06.11.png


下記からRailsInstallerをDLしてInstallして、、っていう感じ。

http://railsinstaller.org/



DL

まんまDL。 だいぶ重い。

スクリーンショット 2012-06-12 17.06.49.png



起動と導入

Macだったらダブルクリックで解凍、

スクリーンショット 2012-06-12 18.29.22.png

出来た.appを起動。

スクリーンショット 2012-06-12 18.29.47.png

スクリーンショット 2012-06-12 18.38.14.png

スクリーンショット 2012-06-12 18.45.14.png

おわった!

で、PDF開くと、


スクリーンショット 2012-06-12 18.48.36.png

とりあえず何が入ってるか確かめてみる。

Terminalから、rvm と ruby のversionを確認。

スクリーンショット 2012-06-12 18.50.06.png

おおーはいっとるはいっとる。

rails new してみる。

スクリーンショット 2012-06-12 18.59.11.png

スクリーンショット 2012-06-12 18.59.25.png

ここまで、一つの環境構築エラーも出ずにうまくいく。

これがどれだけ奇跡的なことか。

スクリーンショット 2012-06-12 19.13.18.png

あっさりとアプリの作成が完了。



rails s

スクリーンショット 2012-06-12 22.37.37.png

localhost:3000にいくと(上記ログはもう行った後だが)、

スクリーンショット 2012-06-12 22.39.07.png

以上、さくっと導入まで。



感想

すっごく楽。

wrote 12/06/12 17:16:40

GradleでShellコマンドを実行する


概要

GradleからShellコマンド実行する。

dependなどが指定できるので、Gradleの仕組みの中でbashコマンドとかが有効活用できる。

daemonとして動かしたりする場合に、使う事がある。



手法

文字配列.execute()を使う。


task makeDirectory {
	["mkdir", "somet"].execute() 
}

上記で、gradle実行フォルダにsomeフォルダが生成される。

一応書いておくと、Gradleだと、フォルダ生成は


file('first').mkdir()


とかで出来る。条件とかも細かく指定できる。

mkdir程度だったらこっちを使おう。

参考:逆引きGradle

http://d.hatena.ne.jp/nightmare_tim+gradlerevercelookup/20111027/1319733318

wrote 12/06/10 0:07:59

GWT SuperDevMode試してみた


概要

本物かどうかも知りませんが、使ってみます。

https://vaadin.com/blog/-/blogs/vaadin-and-superdevmode



導入

つらつら下記



1.テスト版らしいGWTをDL

Get a trunk build of GWT, for example this one built today.

とかあるので素直にDLしてやってみる。

http://artur.virtuallypreinstalled.com/gwt-trunk-20120607.zip

スクリーンショット 2012-06-08 12.22.16.png

して放置。



2.MylynをEclipseにインストール

Mylynが無いって言われるので先に入れとく(依存性解決自動では出来ないっぽい)

http://download.eclipse.org/mylyn/releases/latest

をEclipseでアレする。

スクリーンショット 2012-06-08 12.01.15.png



3.現行版VaardinをEclipseにインストール

Vaadinのプラグインのインストールが必要。

通常版のVaadinを先に入れる。

http://vaadin.com/eclipse

をEclipse pluginとしてアレすればOK。

スクリーンショット 2012-06-08 11.34.50.png



4.Vaardinテスト版をDLしておく

Vaadin 7.0.2 jarを用意する

スクリーンショット 2012-06-08 12.14.29.png

最終的に下記からDL

https://vaadin.com/releases?version=prerelease/7.0/7.0.0/7.0.0.alpha2


して、放置。



5.VaadinプラグインからEclipseでApplication作る

スクリーンショット 2012-06-08 12.40.21.png




6.vaadinライブラリを入れ替え

プロジェクト作ったら、その中に生まれてるvaadinライブラリを入れ替える。

vaadin-6.7.10.jar 


と、4でDLしてた Vaadin 7.0.2 jar を置き換えする。

スクリーンショット 2012-06-08 13.38.46.png

続く

いろいろやったら出来たんだけどうーん、、

予想と違った。




wrote 12/06/08 10:39:16

二年後に聞くリスト


概要

今話題になってて、主観で考えてみて、

「あ、今知ると知った分だけ無駄だなコレ、

二年くらいあとにどうなったか聞けば良いや

っていうリストです。


実際に熟成までにマジ2年かかるかもって思ったものも入ってますし、

ハナから否定的な内容な場合もあります。


いい面も悪い面も、特に考えずに思った事として

「あっ二年後でいいや」

って思ったら更新してます。


いわば、「やらない事リスト」です。

アレってどうだったんだっけ、てこのリストを見る事で、

もし入ってれば

「あー俺この時コレに対してこういう見切りしてたんだー納得、じゃ2年後で良いや」

とか判断できるので、やる事のリスト化と併せてお勧めです。


それなりの変化をしたものもあるんで、

そのときは「俺の目間違ってたわー」として記録してます。


あんまりにも昔のやつは記録したっきりで放置してます。


-- New!! --




JSX 12/05/30 21:53:27

来ない。動作効率化はコードの書き方に依存しない。あとはDartと一緒。



Dart 11/12/01 11:22:39

来ない。Googleだから + Client&Server + そのメリットを感じさせない言語スタイル

どうせ飽きて更新されなくなる。

Googleのメイン事業とも関係ない。



Gumroad 12/03/17 02:02:48

使われ続ける道が見えない。2年後に聞く。



SQEX 11/09/11 9:37:56

流石にデッドラインを超えたと見なす。



F岡 11/08/24 10:44:30

なんとなく。古参はともかく、新参は嫌な臭いがする。

思いつきの集合、というか、目的意識の欠如、というか。

なんかホットだから行こうぜ観を感じる。それはMyタブー。



NativeClient

無意図症候群3

Flashの二の舞



Google+

無意図症候群2



NFC

駄目だと思う。Felicaの事例(使われるたびに維持費だけが増大、でも便利だから導入→利益無し)というパターンを聞くに、ニーズがあっても釣り合わないというケース。

今までニーズ自体無いと思っていたけれど、自治体とかでFelicaを導入したいというケースがあり、簡便性を求めるニーズがある。正、簡便性の先の利益が出ないという構造に陥り、死にそうになっているFelicaが居るので、これは終世来ないと判断した。



PSVita

Goから何も学んでいない。


11/08/13 12:40:18


キュレーション

バズワード。



Android

端末差に永遠に苦しむ。そして増える。アップデートが"望まれる"。

特に最後が最悪で、ハードウェア依存にしないと差別化できない業態で

このOS側がアップデートしていくという制約はアウト。

幅広く使われ、かつマーケット全体が冷えて行くと予想。

UXについても同じ原因(多種多様)が原因で、「ブランドになれない」



ChromeOS

来ない。目的が無い。ノートパソコンのプレゼンテーションとしても、

ブラウザで何でもできます へぇ で終わり。 ニーズもブランドも無い。



アプリやろうぜ(Done)



PSPGo(Done)



VIVID FW(Done)



Go

GAEに入った、、けど、さっぱりわからん。ニーズがあるのか。

そしてニーズを獲得した後、どう発展するかがわからん。


node.js

サーバサイドJSはいいんだけど、JS自体に懐疑的なので不明。

利点であるNIOは他の言語や実装利点として残るとおもう。



Traceur

過渡期の産物なので学ぶ必要性無し。



3Dテレビ(Done)



3DS(Done)



Titanium

Androidの部分はオワコンになるだけ。

できる事の明示が進めばかなり有用なものになると思う。


11/01/13 12:40:53



AppleTV(Survived)



CoffeeScript(Survived)



HTML5(Survived)



SpringRoo

設定ファイルが多いので採用しない。



Flash(Done)



SocialBookmark

息してない



Google eBooks

Gの意図があれば発展、無ければ消滅すると思う。でもGって無意図症候群だからなあ、、



PS3

据え置き機自体のトリを飾って消滅する、最後のハードだと思う。



ソーシャルメディア

バズワード



ソーシャルゲーム

今後草分けが始まる



KIN(Done)



Wave(Done)

本気でタダのデザイン不足。UI変えれば素敵。だった。もう居ない。



Latitude


-- Old!! --

wrote 12/06/03 21:48:14

BlenderからCSSアニメーション作るプラグイン、csstransformexport


概要

社のひとから教わりつつBlenderしてる昨今。

BlenderのアニメーションからCSSAnimation吐くプラグインの話。

@neko_manma1 が呟いてたのをキャッチ。


オリジナル

Blenderのプラグイン。最新の2.63でも動いた。


https://github.com/jamesu/csstransformexport


exampleとかは2年前のものだが、

プラグインの最終更新は12/06 時点で二ヶ月前。



サンプル

オンラインで見れるものが無かったので

githubから引っ張ってDropboxにupした。


CSSで画像一枚を移動、回転、拡大縮小

https://dl.dropbox.com/u/7807380/shared/examples/testImage.html


人形っぽいのが歩く

https://dl.dropbox.com/u/7807380/shared/examples/walk.html



可能性を感じる所

GUIでそういったAnimationを作れるツールとして魅力を感じる訳だが、


Blenderのアニメーションをキーフレームとして出力してるので、

物理エンジンとかと組み合わせた結果を描画する、

的なところにもグイグイくるものがある。


導入

今度bsurfaces_v15_for_blender_263と併せて纏める。

こういう手順系の為にgitMovieはやく作りたいなあ、、


wrote 12/06/02 19:30:49

原研哉さんのデザイン論聞いてて


概要

個人的なメモ。ざっくり書いてるものなので、毒にも薬にもならないと思う。



Globalとは

日本の文化を持って行く、のではなく、

何が役に立てるか、

not Grobalization。


神社デザイン

空っぽの中に、神様が居るかもしれない。

Emptyの運用、Adium


シンプルとは

西洋:国は王のもの→みんなのもの、みんなのためのサービス

この変化が「シンプル」というもの。

権力がある事を示す為の、「細かく」「膨大な時間を要して」「一級の人間が」というものから、変化。


(こういう文脈的な考え方を単語の源流に対して行った事は無かったので、

知るきっかけになって大層ホクホクしてる)



日本:シルクロードを経ていろんなものを受ける「受け皿」の位置

なのになぜ簡素なのか。



が、東山文化の直前に大火でいろんなものを喪う

→京都・東山文化


空っぽ、を含んだもの

何も無いのがかっこいいかも、という価値観


not simple, empty



例:茶室

居る人のイメージで解釈しあう空間

「どんな文脈にも寄り添う」

梅の屏風のある茶室 > 梅の花が綺麗ですよね > マジ梅空間

ヘルケンのナイフ vs 柳刃包丁


片や一体整形の刃、

片や刃に棒がついたもの


「出来るだけ何もしない」「何かの気付き」

「何でも無い、がリッチに見える」



何かデザイン展のはなし

わき出す水滴のロゴ、撥水生地のプレゼンテーション

吹くと流れて落ちる。キモチ良さそうだった。


精密さ、緻密さ、潔さ = おもしろい日本

vs

日本人が思ってる日本

これらは異なる。



HouseVision

デザイナーの役割は、可能性を、目に見える形にすること。

(テクノロジーデザイナーとかあると嬉しい職な気がする)

欲望の品質、欲望のエデュケーション


ニーズに従う vs 予想を超える

使う人たちにエデュケートをさせるデザイン



リノベーション+ソーシャル 

家は多様な産業の交差点

(この、交差点という言葉がとってもすとんと落ちました。)

モビリティから変わる家

玄関から段差がある事で、CleanとDutyが変わる。


住宅リテラシーの成熟。 デザインによるエデュケーション。

それがデザインの目的

アクティブな老人をデザインすると楽しそう。「すばらしいリファレンスになるのでは。」


美意識資源の運用



こんどの、展覧会のようなデザイン

具現の場所 「こうだったりして! が叶うところ」



考察:自分にとって、どこが交差点か

TransitPoint

考えると楽しそう。


言い換えると、

「ここに自分が関わりたいもの達が集まって来ると思うんだ」ってポイントを探したり作ったりして、なにか起こしたり起こったりするわけで、

戦略の中心探しのメソッドにちょうどいいなあと。


wrote 12/06/02 16:31:22

GradleでJarをRunしたり


概要

GradleからJarファイルをRunしたりする話。

Gradleに統合されてるantを使う。


手段

予め、「実行したいJar」をbuild.gradleのそばに用意しておく(MavenRepo上ならDependency書いとく)

とかする。

taskを用意して、その中でJarを実行する記述として下記を入れる。

下記だと適当なタスクsomeを用意した。


task some {
	ant.java(classname:'com.kissaki.MDTestRunner', failOnError: 'true') {
		定義
	}
}


failOnError設定で、jarの実行fail時にエラー扱いにするかどうかが指定できる。

他にもforkだったり


argsなどは、

task some {
	ant.java(classname:'com.kissaki.MDTestRunner', failOnError: 'true') {
		arg(value: "val1")
		arg(value: "val2")
		arg(value: "val3")
	}
}

みたいに書き込む事が出来る。

肝心のJarの場所指定は、Gradleの規定に基づいた方法で指定できるんだけど、

srcフォルダとかの中だったら、そのまま

task some {
	ant.java(classname:'com.kissaki.MDTestRunner', failOnError: 'true') {
		arg(value: "val1")
		arg(value: "val2")
		arg(value: "val3")
		classpath {
			pathElement(location: 'src')
		}
	}	
}

とか書ける。



wrote 12/06/02 12:35:34

MacHaskellを動かす


概要

Mac OSXにHaskell動く環境インストールする。



導入

インストール方法について、調べてるといろんな方法がある。

HaskellWiki

http://www.haskell.org/haskellwiki/Mac_OS_X


スクリーンショット 2012-05-29 18.58.12.png


エディタを整える

TextMateのbundleがあったので利用してみる。

https://github.com/textmate/haskell.tmbundle


Cloneして出来たこんなのスクリーンショット 2012-05-30 15.22.07.pngをダブルクリック



.hsファイルを作成

TextMate > 新規ファイル > untitled.hs を作成

main = putStrLn "Hello, World!"

スクリーンショット 2012-05-29 18.45.35.png

⌘+r で実行

スクリーンショット 2012-05-29 18.45.41.png

わぁい。



wrote 12/05/29 18:05:30

MavenとGradleを比べてGradleがいいんじゃないかなって思う理由


概要

すっごく前に作って安定稼働していたMaven(作った奴もこれ以上変えたく無いやつ)

を、ついに必要な部分だけGradleに変えた。


そのモチベーションになった

MavenとGradleの違い

について書く。


かなり致命的なレベルでいろいろちがう。



設定ファイル vs スクリプト

どこかでだれかが言ってたとおり、

MavenとGradleの最大の違いはそこかな、って自分も思ってた。

Mavenは設定ファイル

Gradleはスクリプト。


自分で手を汚してみた結果、

差分の表現としてはちょっと足りないかな、って思う事がこの移行に際してあったので、次に挙げる。



エラー検出力

設定ファイルのミスを見つけるのがmaven。

スクリプト実行の内容エラーを吐くのがGradle.


設定ファイルの出す答えって、処理内容単位でのOKかErrorの二択だよね。

ずーっと人任せだったんで、ほぼ初めてmaven触ってみた時の感想として、

判りづらい!!! って思ってしまった。


Gradleだと、プログラムを順次実行してく感じになる。

どこでエラーが出たか、については、ここまでは同じ。

で、Gradleだと行にprintlnとか入れられるのです。

何処まで行ってどんな状態か、判る訳です。



エラー出力内容

Maven、何かあるとwikiに行けって書いてあるのは超イラついた。

追跡構造はしっかりしてるので、特に問題は無いと思う。

プラグイン読めば良いんじゃないの。そして絶望すればいいんじゃないの。


プラグイン内でエラーもみ消される事の方が多くてその辺については本当救いようがない。


Gradle、行単位でエラー見れる。

が、エラー発生時には、Gradleのエラー表示も出て、それで根本的なエラー原因をシークする時間がちょっとずつ掛かるのが戴けない。

もしかしたらGradleのエラー表示部分だけ避ける、とかオプションあるのかな。



フォルダ/ファイルの扱い

プラグインがJavaで書かれていて内部でJavaプログラムでファイル作ったりするのがMaven

全部スクリプトで書かれてるのがGradle


正直、Maven触って一番がっかりしたのがフォルダ/ファイルに関して。


TODO:今まで触ってくれてたkrmdに感謝と懺悔の意を込めてメシおごる。


Mavenの「基礎コンテキスト」領域には、フォルダ・ファイル操作系APIが無い。


プラグイン内でファイル操作が必要なら、File.ioをインポートしまくり。

そこら中の.javaファイルでインポートしまくり。

Javaに限らないけど、プログラムでファイル処理扱うのってまず第一級の鬼門でしょ。


なぜならファイル処理は前提の多いシーケンシャルな処理だから。

有無を確認、正当性をチェック、フォルダか?、ファイルか?

その時どんな状態か、というのをValidateする必要に追われる。


そんな鬼門コードが、個別に書かれた複数のプログラムとして至る所にある

個別にFile.ioで、読んで吐いて書き換えて消して。

ダメだろ。


全体的にファイルインプット/アウトプットについて扱う、大枠を用意して、

できるだけ一つのコンテキスト内でファイル作ったり消したりコピーしたりしましょうよ。


Write Everywhereになっちゃう処理があるってことは、それを上位に持ってこないと酷い目に遭います。

同じ処理を別のファイルに2つ書いた時点で気付こうぜ。


おかげさまで、

Create/Delete処理が各Java/Classファイルに分散、全体像が把握しにくい。

エラーチェックが部分部分になる。(Javaでtry~catchしても握りつぶすだけでしょクソが)

チェックを多重化せざるを得ない(チェックコードが増える、それもケース判断を限られたアスペクトで。無理。)

Javaのダメなとこスケールしてんぞコラ。しかもオートだ。

こんなものが世界中にばらまかれてるかと思うと虫酸。


フォルダ/ファイル扱うのが不自由ってだけでもう断定するけど、

Mavenは、依存性解決設定ファイルとそのビルダーであって、

アーキタイプ作成ツール/他に「なってはいけない、向いてない」


Gradleだと、FileIO系はデフォルトでAPIとしてGradleが動作する環境内にある。

ので、処理がばらける事は(デフォルト使ってくれれば)無い。


デフォルトで用意されてれば使うでしょ、ってのは理想論だけど、少なくとも機能が考慮されてる。

そうあれ、とデザインされてる。


ユーザー全体が同一アスペクト内でファイル操作が出来るメリットは、Mavenの抱えるデメリットが無い事。

どこかに書かれてる筈なんだ、とPluginの素のJavaファイルをがさごそすることは、無い。

エラーも、必ず最前面に出て来る。少なくともtry~catchが存在するのはgradleファイルだ。



プラグイン作りの難解さ

Mavenだと、プラグイン用のpom書いて、Javaソース書いて、コンパイルして、パッケージして、

手元環境だったらinstall→実際に使うプロジェクト側でmvn なにやら

めんどくせーーーーーーーー

そしてソースコード多ーい。 File.io多ーい。


Gradleだと、まだ数作ってないですけど、

ぶっちゃけスクリプトだから書いて実行すればいいんだわさ。



まとめ

比較うすッ!! まあ俺が苦しんだのがこの程度の事だったんです。


そんな薄い結論:

ビルド+バージョンを纏めておく為の機構としてはMavenいい子。

それ以上の何かを求めるならGradleが良いと思う。


Mavenは、自分は何処から聞いたか忘れましたけど、

「ビルド+Archtypeとかが色々出来るツール」として聞いてたんですが、これ、ビルド以外全部無理でしょうや。

プロジェクトのビルドに関するArtifactバージョン定義と依存性解決ツール

ってだけだ。

Archtype生成や、test結果のGenerateの為には、どうしても「ファイルを扱う」ってのが

要件に入るのに、それを各プラグインのコード内で対処しようとしたのが設計ミスってると思う。

尻拭いとして「凄く良く様々なケースで失敗する」ってのが出てきちゃう。

裏を返せば、「ハマると強い」なんだけど。ハマる所が狭いだけでしょ。


それって、「想定できてる奴しか出来ませんしその条件ってのも暗黙化しててほぼ明示しませんけど、

使いたければどうぞ、探ってw 試してw 読んでww 苦しんでww」っていう。


お勧めされたら、

「ぜひ一人でお苦しみください」って返したい気分ですはい。


Gradleは、Mavenに出来る事は全部、Mavenよりスマートな方法で出来る。

後出しだからね、、!!

Architype作り、プラグインでのファイル制御、前提エラーの出し方、これらは、 Gradleの方が苦労も痛みも少ない。

コード=スクリプト=実行内容だから、そこに書いてないことは起こらない。



終いに

今までMavenを頑張って書いてきた人に敬意を表する。

凄いよ。大変だったでしょ。

もう、難しい方法でファイルとか扱わなくていいと思います。

File.ioをインポートしまくらないで良いと思います。


プラグインJavaで書いて、コンパイルして、それを含んだプロジェクト側でmvn なにやら。

大変だったでしょう。


build.gradleに何か書いて、gradle なにやら でOKになるんで。

もう苦しまなくていいんだょ。


wrote 12/05/27 18:03:20

emscriptenを動かしてみる


概要

簡単な纏めまでに。

あんまり人の環境とか汚したくないので、全部「どこかのフォルダ」に纏めていれるよう、

cd emsTest とかやってから実行してるものとします。



LLVM

curl -O http://llvm.org/releases/3.0/clang+llvm-3.0-x86_64-apple-darwin11.tar.gz
tar -xvzf clang+llvm-3.0-x86_64-apple-darwin11.tar.gz
rm clang+llvm-3.0-x86_64-apple-darwin11.tar.gz



node

必要。要らなく出来ないかなあ、、



emscripten自体をinstall

git clone git://github.com/kripken/emscripten.git



コンパイルする対象を用意

手始めに、helloworld.cを用意。

#include <stdio.h>
int main()
{
	puts("Hello World");
}



実行

cd emscripten
./emcc ../hello.c 

    

で、適当にソースコードを宛ててみるも、

FATAL: Cannot find /Users/tinoue/Dev/llvm-3.0/cbuild/bin/clang++, check the paths in ~/.emscripten

っていわれる。確かにそんなフォルダはない。

デフォルトで併せてあげてもよかったんだけど、めんどいので設定ファイルを弄る。


件の bin/clang++ 自体は、

emsTest/clang+llvm-3.0-x86_64-apple-darwin11/bin

に展開されてるので、

emscripten側のpathを書き換えるだけ。


自分だと、次の2行を弄った。

EMSCRIPTEN_ROOT = os.path.expanduser('~/emsTest/emscripten') # this helps projects using emscripten find it

LLVM_ROOT = os.path.expanduser('~/emsTest/clang+llvm-3.0-x86_64-apple-darwin11/bin')


     ./emcc ../hello.c 

とかやると、

emscriptenフォルダ内にa.out.js吐けた。

スクリーンショット 2012-05-21 18.26.38.png



wrote 12/05/21 17:38:30

Something to JS まとめ


概要

主にBrowserで動く[言語AからJSを作り出すツール類]を纏めとく。

ただ単に人に説明する時リスト的なものが無くて

面倒くさくなったためカッとなって作っていたんだけど

物凄く良いリストを教えてもらったのでup


https://github.com/jashkenas/coffee-script/wiki/List-of-languages-that-compile-to-JS



以下自分が触った事あって書く意味あるかなーと思う奴だけ抜粋



GWT

https://developers.google.com/web-toolkit/

JavaコードからJSを出力。

JSとの橋渡し機能有り。



ocamljs

http://code.google.com/p/ocamljs/

OCamlがJSに変換される。

JSとの橋渡し機能もあるらしい。



ClojureScript

https://github.com/clojure/clojurescript

ClojureからJSに変換。



BicaVM

http://badassjs.com/post/12648021003/bicavm-a-jvm-implementation-in-javascript

JSで書かれたJVM。



emscripten

https://github.com/kripken/emscripten

コードをLLVMを通じてJSにコンパイルする。

強烈にマニアックだけど、これでJVMをJS化すればいいんじゃねえのと

考えてる。次試す。



Doppio

http://int3.github.com/doppio/about.html

Coffeeで書かれたJVM。

デモすら動かしてないのでホントに動くのかどうかは知らない。



以下おまけ

JS to Coffee

http://js2coffee.org/

JSをCoffeeに変えてくれるサイト。



これ以外にも「こんなのあるよ!」って言うのがあったら、

続 @toru_inoue まで教えてもらえるとたすかりんこ。

wrote 12/05/20 23:50:39

GWTをおすすめする/しない について


概要

GWTについて、自分が考えている事を纏めておく。

・どんな人にお勧めするか

・どんな人にお勧めしないか

を主眼にする。



自分の目、判断基準について

チーム戦を前提に機構やルールを組み上げる仕事をしてるので、

自分の主義主張に関して、

「えっそれ個人なら問題にならなくね?」というコトがありがち。


それでも、自分にとっては、数日前の自分ですら他人(覚えてない自信がある)なので、

・如何に暗黙のルールを自明にできるか

・如何にルール遵守を自動化できるか

・どうしても手でやらなきゃならないとして、如何にルール自体の数を減らせるか


というのが、自分にとって必要な理だったりします。

判断基準として共有までに。



前提、GWTとはなんだったのか

Googleが作った、WebToolKit

略してGWT。

.javaファイルに書かれたjava+jsソースを、jsに変換する。


単純に書くと、

Javaを使って、ブラウザで動くアプリのコーディングができる


なんか気を利かせて、各ブラウザ向けのコードを吐いてくれたりする。



圧倒的な利点

・Javaの言語的なルールをもってして、JSを構造的に記述できる

→妄信的にコーディングルールを定めてクソみたいなJSコードになるよりは、

Javaというカチカチした言語のルールの中で記述する方がマシ。兆倍マシ。

が、これはGWTだけの利点ではなく、他の言語→JSを出力する仕掛け、でも実現できる。

LLVM to JSとか、ClojureScriptとか。

Dartはまだ仕様カチッとしてないしGoogleだから気にしない。


上記 恩恵として、大規模なWebクライアントを書く事が可能。あくまで可能性だけど。 

ブラウザでやった方が良い事、ネイティブでやった方が良い事、サーバでやった方が良い事、の3つがあり、

そのうちの一つが強大になって行くのを担保できる、という利がある。

はっきり言ってJSでのブラウザ巨大アプリは、作らないでいいなら作らないでいい方が本当に良い

でも、って場合、Javaのルールがある程度の助けになる。素のJSよりマシ。


・JavaでJSのテストが書け、ブラウザで実行できる

→JSで書いたライブラリを内包して、薄いラッパー書いてテストをJavaで書いて自動化、なんてことができる。



圧倒的な損点

・手法としてまどろっこしい

→実際まどろっこしい。変換行程は省けないし、変換アクセラレーションも限界がある。

でも、CI組んじゃえば割とどうでも良かったりする。


・Javaちゃんやっぱりちょっと、、ご免っていうかめんどくさい

→ハンドラとか書いてると挫けそうになる。メッセージング無いし。


・Googleプロダクトにありがちだけど、未来が不明

→が、すでに基礎を行うには十分なリソースがそろっていると言える。

JSでHTML5の機構を書いて、Javaでラップ、テストを書いて作って使う、なんてことも可能。

ぶっちゃけ未来なんてどうでも良い、と言える。

いっそ手放してくれたほうが、、、ほら、Waveみたいにさ、、

(ツールとプロダクトを一緒くたにすんなっつう反論はご尤も。)



GWTの現状

HTML4のブラウザアプリならそのまま使用OK。


HTML5の機能に対応するモジュールとかは無い、が、自力で足せる

リリース予定などのスケジュールが未定、そもナニしたいのか、リリース方針が未定


以上をふまえた上で、



自分がGWTをお勧めする人

初学でない + 

Java書けて + 

JSで大規模なものを作るのに苦を感じる + 

テストをする事に重要性を感じて + 

大穴で、JSの損点が他の言語のルールを使う事でどのように補完されるか見たい + 

な、人。


余談だけど、GWTが吐き出すJSが読める、ていう能力の必要はねーと思う。

バグったらJavaのコードをまず疑うべく。

どうせJSのコードを手で直す機会は絶対に訪れない訳だし。


ただし、現在12/05/19 16:09:54 ですけど、

1年後には誰も使わなくなってる言語になってると思います。


理由は、「他の ToJSCompile言語なりツール」が出て来るから。っていうかもう出てきてるんだけどさ。


なので、GWTは、「JavaをJSに変換する唯一の手段」ではなく、あくまで「JavaをJSに変換する1手段」でしかありません。

そこんとこよろしく。


別の選択肢があるなら別のを学ぶと良いと思うよ。



自分がGWTをお勧めしない人

初学 or 初学でない + 

Java書けない or Javaキライ +

JS好き or JSで大規模なものを作るのに苦を感じない +

別にテスト無くても大丈夫! だぜな +

日本語でおk +

な、人。


上記に該当する人は、根本的にお勧めしません。



初学ならこんな難しいものやるより、Coffeeとかのほうにしましょう。

JavaキライならGWTはJavaなのでBye! です。


JS好きならJS書いててください。コールバックコールバック。


別にテスト→そのコード、ずっと動くと良いね! JSでね!! ククク

日本語でおk→GoogleがGWTの死霊を1.6くらいで他言語化放置してるので、やめた方がいいよ。

以上。



In Other Words

GWT is already completed. and Dead. RIP.

please choose the other one.

wrote 12/05/19 15:28:58

大嫌いなmavenのリポジトリの依存関係を可視化する


概要

maven、

pom.xmlが偏在しててムカつきます。

.svnと同じ愚を冒している気がしてなりません。


でもいいの、、、わたしにはGradleがあるもの、、!!


とはいえ仕事なんで、内容とか問題があれば見なきゃいけないんですが、

手で開いてると発狂するので、ツールで見る事にします。



使う形式

graphml形式を使います。

http://graphml.graphdrawing.org/


この形式を選んだ理由は、近所に知ってる奴が居たから。


自分が気に入ってるビューアは下記

gephi

https://gephi.org/


mavenでgraphml形式で依存をoutput

mvn dependency:tree -DoutputType=graphml -DoutputFile=dependency.graphml

で、指定したフォルダに dependency.graphml ファイルが出来てる筈です。



読ませようとするとエラー

上記ファイルをgephiで開こうとすると、

Content is not allowed in prolog. 

とか言われます。saxパーサでエラーが出てる。

で、ファイル見てみたら、saxパーサで読むとは思えないデータ形式。


こんな感じ


org.codehaus.mojo:XXX:XXX

+- org.apache.maven:maven-project:jar:2.0.9:compile

|  +- org.apache.maven:maven-settings:jar:2.0.9:compile

|  +- org.apache.maven:maven-profile:jar:2.0.9:compile

|  +- org.apache.maven:maven-artifact-manager:jar:2.0.9:compile

|  |  +- org.apache.maven:maven-repository-metadata:jar:2.0.9:compile

|  |  \- org.apache.maven.wagon:wagon-provider-api:jar:1.0-beta-2:compile

|  \- org.apache.maven:maven-plugin-registry:jar:2.0.9:compile


ただ、mavenでの実行自体にエラーは出ていない。

カンで、「もしかしてバージョンあるんじゃね?」って思って、

バージョン指定する下記設定をpom.xmlのbuildブロックに書き足した。


<plugin>
	<groupId>org.apache.maven.plugins</groupId>
	<artifactId>maven-dependency-plugin</artifactId>
	<version>2.2</version>
</plugin>



完成図

出力されたファイルはxmlっぽくなってて、gephiで開くと下記みたいな。

スクリーンショット 2012-05-18 21.26.46.png



今後

Gradle版も出せるようにしたいです。そのうち探す。



参考にしたサイト

http://www.summa-tech.com/blog/2011/04/12/a-visual-maven-dependency-tree-view/

モロにバージョン指定について書いてあった。

wrote 12/05/18 21:38:35

XMLをJSONに変換したらまだ読みやすかった件および経験について


概要

XMLの可読性の低さがキライです。


なんで開きタグと閉じタグが必要なんですか?

アトリビュートとかそういうのって選択肢無駄に増やしてるだけで読みにくいです

馬鹿なんですか。 死ぬんですか。

(個人差があります。)

で、ビジュアライズするツールを探した。


要件は、

・Webサービスである事

・xml本来よりまだ見やすい表現方法であること



探し方

ここに一番詰った。これを書きたい。


最初、xml visualization でググって探した。


xmlの内容を読みやすくできればいいかなーと思ったので。

visualizeであるかなーと。


そしたら、

なんでかオンライン表示ツールは存在せず、

ダウンロードして動かしてね的なツールが山のように見つかった。


stackoverflowですら、GUIツールを提示してきて絶望した。


もちろんそんなものに用は無い。

たかだか可読性をあげるためだけに、何かインストールして見るとか厭だ。

しかも対象はxml。

絶対に厭だ。



で、考え直す

落ち着け、素数を数えて落ち着くんだ。

ぶっちゃけxmlの形式が読みにくいだけなんで、ほかの形式に変える、

そう、そういうアプローチにしよう。

って探したら、すばらしい事に最初の目的

・xmlのビジュアライズを行うツール

に巡り会えた。



今回の神

XML-JSON相互変換ツール - Bluehawk's lab.

http://bluehawk.infinitybird.com/dev/xmljson.html


おかげさまで読みやすいです。

JSONオブジェクトを階層表示で表示可能で、xmlをビジュアライズしたかった事も叶いました。


参考までに。


xmlのクソデータ


<?xml version="1.0" encoding="utf-8"?> 

<areaData title="サンプルデータ">

  <hrTitle1 title="見出し1" no="0">

    <hrTitle2 title="見出し2a" no="0">

      <hrTitle3 title="見出し3a" no="0">

       <listItem>テスト</listItem>

      </hrTitle3>

      <hrTitle3 title="見出し3a" no="1">

       <listItem>テスト</listItem>

      </hrTitle3>

    </hrTitle2>

    <hrTitle2 title="見出し2b" no="1">

      <hrTitle3 title="見出し3b" no="0">

       <listItem>テスト</listItem>

       <listItem>テスト</listItem>

       <listItem>テスト</listItem>

       <listItem>テスト</listItem>

       <listItem>テスト</listItem>

      </hrTitle3>

    </hrTitle2>

  </hrTitle1>

</areaData>



jsonのまだ赦せるデータ


{

  "areaData": {

    "-title": "サンプルデータ",

    "hrTitle1": {

      "-title": "見出し1",

      "-no": "0",

      "hrTitle2": [

        {

          "-title": "見出し2a",

          "-no": "0",

          "hrTitle3": [

            {

              "-title": "見出し3a",

              "-no": "0",

              "listItem": "テスト"

            },

            {

              "-title": "見出し3a",

              "-no": "1",

              "listItem": "テスト"

            }

          ]

        },

        {

          "-title": "見出し2b",

          "-no": "1",

          "hrTitle3": {

            "-title": "見出し3b",

            "-no": "0",

            "listItem": [

              "テスト",

              "テスト",

              "テスト",

              "テスト",

              "テスト"

            ]

          }

        }

      ]

    }

  }

}

アトリビュートもウマい事わけてくれて、助かります。



一つ思いついた事

人間が手を加える前提のファイルと、そうでなくProgramから触れる前提のファイルを、

xmlのクソビジュアル性を使って別けられるのではないか。


人が手を加えたり読んだりする前提のファイルは

xml以外


人が手を加えたり読んだりしない前提のファイルは

xml

コレでいい気がする。

俺の中では、xmlはバイナリファイル。 俺の中ではな。



そんなことよりももいろClojureがいい感じです(脳内で

wrote 12/05/16 12:20:02

GradleからJettyを動かす+Deploy



概要

GradleからJetty動かして、何かしらのServeを行う。



内容

Gradle User Guide

http://www.monochromeroad.com/artifacts/gradle/userguide/userguide.html

の、

10 Webアプリケーションクイックスタート

http://www.monochromeroad.com/artifacts/gradle/userguide/web_project_tutorial.html

を参考に、


"Warプラグインについての詳細は26War プラグイン Jettyプラグインの詳細については28Jetty プラグインを参照してください。 Gradle配布物のsamples/webApplicationディレクトリにサンプルJavaプロジェクトがあります。"


とかあるので、適当にScriptをパクって、試す。


実践

単純に動かすだけなら、build.gradleに、

apply plugin : 'jetty'


と書くだけ、からの 

gradle jettyRunWar

スクリーンショット 2012-05-05 15.10.05.png

と表示されて、Jettyサーバが立ち上がる。

Gradleのwarコマンドと何かを関連づけておけば、このコマンドでwar内の生成物がjettyへとdeployされる。

⌘+.とかで終了できる。



アクセスしてみると、

スクリーンショット 2012-05-05 15.16.24.png

testって名前のフォルダから実行した。

testフォルダ上には、Jettyの構成が出来ている。

スクリーンショット 2012-05-05 15.17.55.png



Deploy

やりたいことは、

・Jettyに何かしらのアプリケーションをデプロイ。

実際には jettyRunWar コマンドは、warコマンドで生成したものを

deployする、との事なので、

warコマンドをbuild.gradleに書き加える。


apply plugin : 'jetty'

war {

    baseName = 'someWebApp'

    archiveName = "something"

    from 'war' 

 

    manifest {

        attributes 'Implementation-Title': 'something'

        attributes 'Implementation-Version': 'some version'

        attributes provider: 'gradle'

    }

}


で、

warフォルダーを用意して、その中にindex.htmlを置いてみた。

スクリーンショット 2012-05-05 16.08.26.png

実行してみる

スクリーンショット 2012-05-05 16.07.27.png

war化時のmanifestから、アプリケーション名が反映されているのが判る。

で、

アクセスしてみる

スクリーンショット 2012-05-05 16.09.09.png



run+deployをGradleの中から行う

ここからが本題、上記をgradleの中から行う。

(外側の別のGradleから実行してもいいんだけど、中からコントロールできた方が楽しい。)


実際に求めるコントロールは、

・とある条件を満たすまでは動いていて欲しい

・とある条件を満たしたら落ちて欲しい

という感じになる。

立ち上げっぱなしに対してタスクを与える的な動きは今回は意識しない。

参考として、JettyPluginConversionッつー規約集があったので、目を通してみる。

http://www.gradle.org/docs/current/javadoc/index.html?org/gradle/api/plugins/jetty/JettyPluginConvention.html

この時点でのbuild.gradleがこんな感じ

apply plugin : 'jetty'


war {

    baseName = 'someWebApp'

    archiveName = "something"

    from 'war' 

 

    manifest {

        attributes 'Implementation-Title': 'something'

        attributes 'Implementation-Version': 'some version'

        attributes provider: 'gradle'

    }

}


task jettyRunTasks << {

/*    httpPort = jettyConfig.port*/

println "jettyRun before..."

//mada yoku wakatte nai

    jettyRunWar.daemon = false //no effect

println "getWebApp "+jettyRunWar.getWebApp() // /Users/sassembla/Desktop/test/build/libs/something

println "getJettyConfig "+jettyRunWar.getJettyConfig() //null

// jettyRunWar.restartWebApp(false)

// jettyRunWar.createServer() //creates something,,

jettyRunWar.startJetty() //Run!! but with eror..

// jettyRunWar.startJettyInternal() //same above

println "jettyRun...after"

}


wrote 12/05/03 19:30:05

JVMに渡っているArgumentを見る


概要

とあるJavaアプリケーションの起動時に渡っているargumentが気になった。



わからねぇ

Eclipseで見てみる。


実行前のargumentの欄が空っぽで、まあそんな訳ないだろうと思う挙動をしてる訳ですが、

デコンパイルしたコードをちょっと見てみたら、パラメータを足しまくっている。


しかも上書きしたりtry-catchでリセットしたりしてる。そこかしこで。


えーこれどこが末端か調べるのも大変だし、そもこの環境でコンパイルして実行できる保証が無い。


さて、、どうやって調べたものか、、

Pasted Graphic.pdf

たすけてください! たすけてください!! (地下鉄でうどんの束を大事そうに抱きかかえながら)




(全裸の)うらがみさんが助けてくれた(全裸で)

1__#$!@%!#__Pasted Graphic.pdf


そんなjps

http://java.sun.com/j2se/1.5.0/ja/docs/ja/tooldocs/share/jps.html


jps -v

で、こんな感じに表示された。 

スクリーンショット 2012-05-01 15.31.36.png

例だけど、これだと、DevModeって名前のプロセスが動いてて、引数はこんな感じ。

なるほどなー!!



くいしーさんが助けてくれた

Pasted Graphic 1.pdf


Debugから見れたのか、、、知らなかった、、知れてよかった、、

こんな感じに見る事が出来た。

(下のは、実際に知りたかった奴ではないんだけれど、手近にあったGWTの実行時のDebugビュー。)

スクリーンショット 2012-05-01 15.20.21.png



感謝!!


wrote 12/05/01 15:29:31

Pharo


概要

OpensourceのSmalltalk実装

http://code.google.com/p/pharo/

そもそもSquarkに興味がある


日本語の紹介記事

http://news.mynavi.jp/news/2012/04/25/021/index.html

wrote 12/04/30 18:09:10

lein-cljsbuildを使ってみた


概要

https://github.com/emezeske/lein-cljsbuild



出来るかどうか期待している事

ClojureScriptのセッティング簡単化

wrote 12/04/30 17:41:30

GWTのテストをGradleで行う、のまとめ

概要

GWTでのテストは、通常Eclipseなどと連携して行われる。

オートマチックに行うには、antを叩く、とかすればOKなのだが、

それをGradleから行いたい。



自動化するテストの種類

GWTには複数の実行時モードと、さらにテスト環境による派生がある。


モードは、

JavaでJUnitをそのまま実行するモードと、

JavaからJSへと変換を行ってから実行するProductionModeの2つ。

環境は、

HTMLUnitと、

実ブラウザを使用してのモードの2つ。



ぶっちゃけJavaでテストしてもロジック部分しかテストできない+

HTMLUnitだとテストできない項目が多いので、


JSで、複数の実ブラウザ上でのテストを行う。



モチベーション

主なモチベーションは、GWTで書いたものが自動的にブラウザ上でテストできる、

なのだけれど、

GWTの仕組みを面白おかしく使えば、

既存のJSライブラリ や新規JSライブラリ、HTML5の機構を使った部分とかも

Javaでテスト書けるうえに実ブラウザ上で実行できる

ので、こう、なんだ、うれしい。

さらに修羅の道を歩むと

テストだけを特定のモバイル端末に送り込み、結果を集計してテストマスターに返す、

なんていう仕掛けも可能だったりする。

もちろんJavaで。


こういうことは得意なJavaで。



GWTのコンパイルの中身から、それらを自動化する算段をたてる

ぶっちゃけやる事はantです。xmlです。☆になれば良いですね。


GWT自体のビルドについての解説はこちら

http://sassembla.github.com/Public/12:03:11%2018-56-27/12:03:11%2018-56-27.html


で、テストケースをJUnitで書いて、依存性解決してビルドして走らせれば、それがテストになる、というのがJUnitとかの特徴。


GWTでは、特にGWTTetcaseというクラスを拡張してJUnitのテストを書くことになる。


wrote 12/04/30 14:15:30

ShellでJSONを使う


概要

Shellでモノを作ってて、受け渡す値とかをJSONにしたくなった。

Shellでそんなものまさか無いだろう、と思ったらあったので、記録までに


コレ

https://github.com/dominictarr/JSON.sh



使い方

JSONのparseだけが出来る。

で、pipeでその後の取得処理とかを書くという面白スタイル。



サンプル


リソース(params.json)

{
	"marker":"p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 22.0px",
	"picker":"<p class=\"p1\">"
}


./JSON.sh < params.json


結果

["marker"]	"p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 22.0px"
["picker"]	"<p class=\"p1\">"
[]	{"marker":"p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 22.0px","picker":"<p class=\"p1\">"}	

こんな感じに、[key] (tab) value になる。


使い方

./JSON.sh < params.json | 全キーを取り出す式


とか

./JSON.sh < params.json | キーAを使ってバリューAを取り出す式


とかやってた。

サンプルのmarkerが欲しければ、

./libraries/JSON.sh < params.json | egrep '\["marker"\]' | cut -d'	' -f2 | sed s/'\"'//g


wrote 12/04/27 0:48:40

Shellのテストについて


概要

Shellに対して使えるテストがあると聞いて。


参考

http://d.hatena.ne.jp/yohei-a/20100202/1265058239

ブツ

http://code.google.com/p/shunit2/



対象

下記githubに上がっているものが対象

https://github.com/sassembla/Public

の、

gh-pages ブランチ。

publi.sh シェル。



導入

纏めているところ、、、

wrote 12/04/27 0:06:47

Twitter @anywhereでブログのコメント欄っぽいものを作る


概要

necomimi publishに手軽にコメント機能を付けようと思ったので、実行。


参考

http://ichitaso.blogspot.com/2012/04/twitter-anywhere.html

試しにこのページに実装してみます。

@toru_inoue



手順

1.Twitterに登録

2.anywhere用のscriptを埋め込む

Unknown.jpeg

先にシェルのテスト書いちゃうね。



完成予想

・ページに 

[@toru_inoue (to 12/04/26 2-09-41)  コメントする]

とか付ける

・過去にページに対してコメントされたものを取得、表示する(出来る分だけでいいや)

・各ページに勝手に付くように、footer化する(どう変化するのが一番楽なのか、悩ましい)



メモ

twitter Dev

https://dev.twitter.com/apps/2074317/settings

ブログにした猛者が

http://creazy.net/2010/04/twitter_anywhere.html

wrote 12/04/26 2:09:41

このブログっぽい何かの作り方


概要

適当なフォルダにhtmlとかrtfdとかを集めて、shell実行して

index.htmlを生成。

で、生成後にgithub-pagesにpushしてる。


特に、実行するshellの名前を、厨二っぽく

publi.sh にしてみた。


意味は無い。



publi.sh

しぇる。

このgithub-pageの元になってるgithub-repo

https://github.com/sassembla/Public

gh-pages ブランチから落とすと、入ってる。



コレを作ったモチベーション

Blogの代わりに使いたい。


既存のBlogがめんどくさい。

とにかくめんどくさい。以下の点がめんどくさい。


・画像貼る度にアップロードww お前ww 今21世紀www

・マークアップランゲージ、なにそれ食えるの、また覚えるの。

・書いてる途中に落ちる

・送信したのにウワアァァアァァア

・要らない機能がある

・一度書いた記事の編集とか手動で明示しないといけない面倒い


以上。ろくな事が無い。



改修案

書き手の手に凄く近い所で書いて、それがほぼそのままupされることが望ましい。


また、表現力について、できるだけ頑張りたく無い。

HTML/その他のMLを手で書くとか厭だ。

俺は文章が書きたいんだ。閉じタグとか*とかが書きたい訳じゃない。


画像とかもほいほいupしたい。

コメント、、とかはいいや。まだいらね。



提案する方法

Client上で編集できる

→手元のEditorで、upされる対象を編集できるものを探した。

表現力

→同上。

画像

→同上。


注釈性

→Version管理で過去の版を用意できるようにした。

Github-pagesとかと連携すれば、ホストのURLとかもマトモな感じになりそうだ。


publish性

→他の全要素のコントロールがココに集中する結果になった。

最終的に、

・ルールを決める事

+

・できるだけ簡易に行う事


を満たしたら、なんかshellになった。21世紀なのに。


Usage

まだApplicationとよべるようなものまで洗練してないけれど、

次の3工程で記事をupできる。

・Macについてるコレ (テキストエディット)で、文字を書きなぐる。

スクリーンショット 2012-04-23 1.26.34.png


文字の/フォント変更B(強調)アンダーラインと割と何でもござれ。

標準はrtfだが、html形式で吐き出せる。

そして、html/rtfdのまま、直接開いて編集できる。

publi.shを使うにあたって、簡単に作る為にルールを設けた。


ルールは2つ。

1.22pointサイズで一行目を描く事。

あとでファイルの見出しになる。(この設定はgrepで見てるだけなので、書き換え可能。)


2.html形式 あるいはrtfd形式で保存する事。

画像をD&Dで加えると、rtfdに変えますか?とか聞かれる。

画像を加えるならrtfdでOK。



・publi.shが置いてあるフォルダに放り込む。

こんな感じになる。フォルダで表示さているのが元rtfdのファイル。スクリーンショット 2012-04-23 1.33.12.png

・publi.sh を実行。(下記はTextmateで実行している。)

スクリーンショット 2012-04-23 1.34.04.png

すると、

rtfdがhtmlとimageに分解され、

index.htmlが出来上がり、

github-pagesへとPushされる、という仕掛け。



今後

・対応するファイル形式を増やす

→html,rtf,rtfdに対応した。 keynoteにも対応したい。ppt? pdf? 何それ。

・記事自体の過去ログが見れるようにする

→git連携を描く事で解消するつもり。

・Twitter@anywhere でフッターにコメント機能を実装

→12/04/26 2-09-41 から対応開始

・MacのApplication化する(同一フォルダ内にあるhtmlとかrtfとかwordとかkeynoteからindex.htmlとhtmlリソースを作り出す)

→一時中断

・コードなどの検知とスタイル付け

→12/04/27 0-48-40 時点で仮完成。

wrote 12/04/23 1:23:37

Gradle勉強会(#1)に参加してきた


概要

兵舎krmdに続いて俺もGradle大好きッ子になってきたので以下略

atndのこれ。

http://atnd.org/events/27023


Gradleからantを設定する書き方と、GWTのステマです。



死霊

http://dl.dropbox.com/u/7807380/shared/antInGradle/index.html

wrote 12/04/22 1:09:02

習慣のつくりかたについて考えてみてた


概要

井上が過去やった・今もやってる 習慣を作るときに試してる事のメモです。


自分にとって利になる習慣を作り出せるかどうか、試してみてた。

始めたのが10年くらい前。忘れてるけど端からみたら習慣、っていうのがまだあるかも。



動機

習慣化すればいろいろ捗るんじゃないかという甘い浅はかな考え。



現状の結論

続く事しか続かない

続いているかどうかを判断する(=ルールを評価する)仕組みが一番大事。



手法

まず、習慣にしたい事を実行します。

つづいたら習慣に出来ているはずです。



具体的には

どんな手段を使っても良いので、「続いているか把握する」方法を仕込みましょう。

自分でもこの手段は一般化できた事がありません。

唯一、「定期的なタイミングを設ける」という、

時間の制約(1w後に考える、とか)が、一番一般解にちかいかなあという感じ。



習慣化出来た事

週でのToDo管理

習慣化した方法:GoogleDocsにやりたい事を週ごとに書く

週ベースのToDoリストとして機能。

宣言でしかなく、Doneの定義を持たないことで、運用が楽になった。

コーディング再開時の思い出しロスを失くす=忘れてOKにする

習慣化した方法:時間地雷

自社採用の仕組みで、「いつ、どこまでどんなコードを描いてたか」

覚えてなくても良くなった。

おかげで、躊躇無く「どこまでやったか、次何をするか」忘れて、

複数のプロダクトに関わりやすくなった。


統一フォーマットでのテキストメモ

習慣化した方法:ファイル名を日時(12/04/21 15:16:10 など)、見出しをつける

テキストでの検索可能なメモをとることが出来るようになった。

いつ、どこらへんのコトをしたか、しらべものの結果は何処か、など。

検索性を高める為の工夫を、単一の記法ルールだけにしたこと、

あとファイル名前付けに悩まなくなった事が続因。


集中

習慣化した方法:時間を計る

大学の頃からやってる方法なんですが、

規定の時間、そのものごとに集中する為に、タイマーを使ってます。

1hをセット、目に見えるとこに置く→時間が来たらアラーム、

続行するならもう1度セット。


別名、殺意駆動開発(嘘)



習慣化出来なかった事

手帳でToDo

持ち物として捨てた方が楽な事が判明した。

(持ちもの少ない方が楽の法則)

具体的にはMBAに食われた。常に持ち歩くのがWebになった。


あとで読むの消費

いつかよむのいつかは永遠に来ない。

ただ、積んでおく事から罪悪感を取り除く事には成功した。

実質この項目はもう諦めといっしょにある。


副作用的に学んだ[続かない理由](逆は真ではない、被験者は俺、という点に注意して見てね)

質量を増やす行為は続かない

持ち歩くものを増やす、というのが辛い場合がある。

ものを失くす事で続く事もある。

ステップ数を増やす行為は続かない

そのためだけの動作を強いる行為は疲れる。自動化で回避できる。

自動化すると、これがスゴくいい感じにハマったりする。


メリットを忘れる行為は続かない

思い出す行為は疲れる。離れる遠因になり得る。


罪悪感駆動は続かない

やらないと「残念!」、みたいなのが続かない。

即見なくなる。だって見たく無い。

罪悪感を軽くする方針にしたら旨く行ったものもある。



習慣化できるかどうか、という判断について

自分が習慣化したいなーと思う事、という希望以外にも、

習慣化するとか思っても見なかったけど習慣化すべきだな、って気づいて、

「とある物事についての習慣化」を考慮したことがあります。

ファイル名付けとかがその類いで、

それまではあーだこーだかいてた訳ですが、

一貫した記法(と、そのためのCoolな入力法)を得るまでは、試行錯誤でした。


勘としては、

・なんどもありそうなら習慣化を考える

・おもいわずらいたく無ければ習慣化を考える

というくらいかなあと。



思う事

ここに描いてある事例って、「俺が習慣化したいこと」から出しているのですが、

「こんな習慣が欲しい」って言葉を初めて使って、もしかしてコレって

凄く「ニーズ」ってものを言い換えたものなのかな、って思いました。


試した数は年20~30くらいなはずなので、

打率的にいうと年2つくらいが非常に長く続く感じ。

それもツールの隆盛や環境の変化によって捨てられたり変化したりします。

一周まわって、「続く事しか続かない」という由来。



続・思う事

いざ習慣になった時、その効果が凄まじいものが何種類かあります。

手放せなくなる、と言えば判りやすいかと。

逆に、「習慣っちゃあ習慣になったけど、効果は薄いかな」と思う事もあり、

結局自分自身ですら、

「欲しいと思った事とやってみた結果が判断できるのは出来てから」

というジレンマに陥ってたりします。


裏返せば「人は、自分がほしいものをありのまま叶えることはできない」なのかなあ、

とも。

具現化の副作用とでも言おうか。


まあ、俺以外の人間は全員俺ではないので、個人的な意見です。



最近習慣化したい事

ブログっぽいものを超簡単に継続する。


具体的には、

・ひとつところに定まったアドレス(http://なにやら)を持ち、

・既存のBlogの嫌いな所(ログインとか記法とか)を排除し、

・必要なインデックス化(タイトルと言及)だけを可能にする

というのを習慣化したい。

テキスト保持の方法論は習慣化してるので、

そこから一歩発展させて、Publishする方法を軽量化できればOK。

Dropboxにコレが置いてあるのも、その一環。

wrote 12/04/21 14:11:41

Parseを使ってみる


概要

BaaS(Backend as a Service) の、Parseを使って遊んでみる。

https://www.parse.com/


BaaSって

Parseの場合、WebServiceの「保存」Persistentを勝手に旨い事やってくれる化・自動化したもの。

iOS/Androidから通信するだけで、特定のKVSとしてデータを保持してくれる。


Parseの場合、データのPersistent以外にも、

・Web側データの管理、表示(課金にひもづくからそりゃあね

・PushNotification

にも対応している。



導入

クイックスタート

https://www.parse.com/apps/quickstart

から、

スクリーンショット 2012-03-28 10.18.44.png

適当に、Parse対応したいアプリの形式を選ぶ

(上だとExisting iOS を選んでいるけど、この記事では New iOS を選択した。)

ParseStarterProject というiOS Project一式がDLされるので、Xcodeで開く。

見てみると、いろいろFWつかってある。あとQuartzCoreはみ出てる。

left.png

チュートリアルどおり、ParseStarterProjectAppDelegate.m > didFinishLaunch にメソッド追加

スクリーンショット 2012-03-27 8.26.54.png

同梱の ParseStarterProjectViewController.h にimport追加

スクリーンショット 2012-03-27 8.27.43.png

ParseStarterProjectViewController.m の viewDidLoadに下記を追加

通信用のオブジェクトを作成、オブジェクト(key-value)をセットしてsaveで、Parse側に保存される。

スクリーンショット 2012-03-27 8.28.12.png

起動してみたところ

スクリーンショット 2012-03-28 10.33.59.png

チュートリアルに戻り、Testってボタンがあるので押すと、さきほど送り込んだKey-Valueが表示される。

スクリーンショット 2012-03-27 8.28.38.png

こういうチュートリアル良いですね。やってた事の意味が分かりやすい。



疑問

通信に失敗したらどうなっちゃうの?


たとえば

[testObject save]


このメソッドはbool値を返してきてて、同期的に通信を行い、正否を返してくる。

通信Offってやってみたらfalse帰ってきた。スクリーンショット 2012-03-28 10.38.47.png

数回リトライし、理由を出力

理由取得の方法は、必要があったら調べて書く。かんたんぽい。


あと、RemoteNotification出して教えてくれるっぽい。実機なら試せる。



使用感未確認だけど楽しそうだなーと思った部分

saveInBackground

saveInBackgroundWithTarget

saveInBackgroundWithBlock

saveEventually

fetch


delete


名前見てるだけで「ヘェ~」ってなるメソッドがいっぱいある。ステキ。



とりあえずiOSだけで成立するようなクライアント限定系のアプリ/サービスをさくっと作る分には良さげ。

wrote 12/03/27 8:29:45

GWTをGradleでビルドする GWT build with Gradle


概要

gradleでのビルド設定など



github

https://github.com/sassembla/GWTandGAEandGradle_SampleProject



Screencast

http://www.screenr.com/YBH8

*Gradleのスクリプトは下記のスクリプトをコピペしてるだけです!

試行錯誤をお見せ出来ずすいません。



手順

スクリーンショット 2012-03-11 18.57.10.png


build.gradle

apply plugin:"war"
apply plugin:"java"
modulename = "GWTandGAEandGradle_SampleProject"
version = 1.0


repositories {
	mavenCentral()
}
configurations { 
	gwtCompile 
}
dependencies {
	println("dependencies start")
	//gwt from maven repo, or local.
	compile "com.google.gwt:gwt-servlet:2.4.0"
    //gwt compiler
	gwtCompile (          
		[group: 'com.google.gwt', name: 'gwt-user', version: '2.4.0'],          
		[group: 'com.google.gwt', name: 'gwt-dev', version: '2.4.0']          
	)
	println("dependencies over")
}


//出力先をwarファイルに
gwtBuildDir = 'war'


task gwtCompile << {
	created = (new File(gwtBuildDir)).mkdirs()
	println "gwtBuildDir	"+gwtBuildDir
	ant.java(classname:'com.google.gwt.dev.Compiler', failOnError: 'true', fork: 'true') 
	{    
		//args settings
		jvmarg(value: '-Xmx512M')    
		arg(line: '-war ' + gwtBuildDir)
		arg(line: '-logLevel INFO')    
		arg(line: '-style PRETTY')
		println "start,,," + gwtBuildDir
		println "configurations.compile.asPath	"+configurations.compile.asPath
		arg(value: 'com.kissaki.'+modulename)
		classpath {      
			pathElement(location: 'src')      
			pathElement(path: configurations.compile.asPath)      
			pathElement(path: configurations.gwtCompile.asPath)    
		}  
	}
}


//dependency add.
war.dependsOn gwtCompile
war {
	println("war start")
    archiveName = "${modulename}.${extension}"
    from gwtBuildDir 
    manifest {
       	attributes 'Implementation-Title': modulename+' Version'
        attributes 'Implementation-Version': version
        attributes provider: 'gradle'
    }
	println("war over")
}
wrote 12/03/11 18:56:27

Gradle with TextMate


概要

GradleをTextMateと連携させて、TextMateから実行する。


TextMate

http://macromates.com/



参考

http://www.breskeby.com/gradlecasts/2011/02/08/33/



TextMateのBundle DL

https://github.com/alkemist/gradle.tmbundle

書いてある通り、

gradlewがプロジェクトにおいてある場合のみ動作する。

TextMateのBundleは、TextMateが入っている状態だと

スクリーンショット 2012-06-15 1.46.47.png

こんな感じに表示される。

どこでもいいので展開するとインストール完了。

TextMate > Bundles に、Gradleの項目が表示されているはず。

gage.png


ただ、これだけだと特に何もいいことがない。



導入手順

・TextMateでGradleのシンタックスハイライトを有効にする

・Gradleのtaskの実行をTextMateから行えるようにする

の順で解説する。



TextMateでGradleのシンタックスハイライトを有効にする

GroovyのTextMate Bundleを入れると、勝手に有効になる。

Gradleで動いてるのGroovyだしな。納得。


Groovy TextMate bundle DL

https://github.com/TextMate/groovy.tmbundle


こんな見た目になるはず。

スクリーンショット 2012-06-15 1.44.19.png

正直もうちょっとなんか有るんじゃないかと思うけど、、わからん。

特に困ってはないのでこれで過ごしてる。



Gradleのtaskの実行をTextMateから行う

本題。

GradleのTextMate Bundleを使うには、

そのプロジェクトにgradlewが作られている必要が有る。


Wrapperって何って人はここみるといいと思う。

http://gradle.monochromeroad.com/docs/userguide/gradle_wrapper.html



プロジェクトのbuild.gradleに、

task wrapper(type: Wrapper) {
    gradleVersion = '1.0'
}

と足して、

gradle wrapper


で、

スクリーンショット 2012-06-15 2.03.03.png

gradleフォルダとかが完成するはず。

これで準備OK、


TextMateを起動、

⌘ + control + g とかやると、メニューが出る。

スクリーンショット 2012-06-15 2.09.04.png


Run Command(project) を選ぶと、下記みたいなウインドウが出てきて、

入力したtaskやオプションを実行できる。

スクリーンショット 2012-06-15 2.10.18.png

実行結果

スクリーンショット 2012-06-15 2.11.42.png

などなど。

これでTerminalとTextMateを行き来しないでよくなった。

wrote 12/03/10 14:21:43

Trigger.io


概要

クロスプラットフォームなFW

http://trigger.io/


この記事みて興味持った。

http://trigger.io/cross-platform-application-development-blog/2012/02/24/why-trigger-io-doesnt-use-phonegap-5x-faster-native-bridge/



セットアップ

サインアップ/インが必要。え。


development environmentとやらをDLして解凍後、

解凍したdirで、

source go.sh


somewhere:forge-tools someone$ source go.sh

Welcome to the Forge development environment!


To get started, change to a fresh directory for your app, then run: forge create

RuntimeにPython2.x系が必要。macだと最初から入ってると思います。

解凍した時点でこんな感じ

スクリーンショット 2012-03-05 9.58.42.png


アプリケーション作成

"To get started, change to a fresh directory for your app, then run: forge create"

っつーことなので、

mkdir ../testApp

cd ../testApp

で、

forge create 


(forge-environment)somewhere:testApp someone$ forge create

[   INFO] Forge tools running at version 2.6.2_

[   INFO] Update result: you already have the latest tools

Enter app name: TestApp

Your email address: sassembla@hotmail.com

Password: 

[   INFO] authenticating as "sassembla@hotmail.com"

[   INFO] authentication successful

[   INFO] Registering new app "TestApp" with trigger.io...

[   INFO] Fetching initial project template

[   INFO] App structure created. To proceed:

[   INFO] 1) Put your code in the "src" folder

[   INFO] 2) Run forge build to make a build

[   INFO] 3) Run forge run to test out your build



この時点で、testAppフォルダ内は、 スクリーンショット 2012-03-05 10.40.03.png


わーいなんか出来たー。

スクリーンショット 2012-03-05 10.40.11.png


Build

forge build


[   INFO] Forge tools running at version 2.6.2

[   INFO] configuration has changed: creating new templates

[   INFO] Update result: you already have the latest tools

[   INFO] Starting new build

[   INFO] Build 2537 started...

[   INFO] This could take a while, but will only happen again if you modify config.json

[   INFO] build completed successfully

[   INFO] current configuration hash is a62f505ab0e63a48963cd677152f175c

[   INFO] fetching new Forge templates

[   INFO] fetching unpackaged artefacts for build 2537 into ".template"

[   INFO] creating output directory ".template"

[   INFO] fetched build into "/Users/sassembla/Downloads/testApp/.template/chrome", "/Users/sassembla/Downloads/testApp/.template/android", "/Users/sassembla/Downloads/testApp/.template/ios"

[   INFO] fetching generation instructions for build 2537 into .template/generate_dynamic

[   INFO] enabled platforms: ['android', 'chrome', 'ios']

[   INFO] <Build (android, chrome, ios)> running...

[   INFO] reading app code from /Users/sassembla/Downloads/testApp/src

[   INFO] writing new app to /Users/sassembla/Downloads/testApp/development

[   INFO] <Build (android, chrome, ios)> has finished

[   INFO] Development build created. Use forge run to run your app.



Run

forge run ios


[   INFO] Forge tools running at version 2.6.2

[   INFO] enabled platforms: ['android', 'chrome', 'ios']

[   INFO] <Build (android, chrome, ios)> running...

[   INFO] reading app code from /Users/sassembla/Desktop/testApp/src

[   INFO] writing new app to /Users/sassembla/Desktop/testApp/development

[   INFO] simulator pid is 41242

2012-03-05 13:13:21.940 iPhone Simulator[41242:707] NSUnscaledWindowMask is deprecated and will be ignored.

[   INFO] pid for iPhone app is: 41252

[   INFO] Showing log output:


ここでSimulator起動

スクリーンショット 2012-03-05 13.14.13.png


いきなり.appが作られた。

device-app.png




む、、ということは、アプリに対するiOSというかObjective-C的な編集性が

みじんも無いのか。

まじで。

→まじだとしたらTitaniumの方がすてきなので、えっと。



いやきっとあるはずだ、、

いくら海の向こう側でBuildしてくれても、これじゃえっとあの、申請自分で出来ない。

updateとかコントロールできないと正直使えない。


Package

特に説明がないんだけど、写真にはうつってるので試してみた!


forge package ios


[   INFO] Forge tools running at version 3.0.1

[   INFO] enabled platforms: ['ios']

[   INFO] <ForgeTask (ios)> running...

[   INFO] reading app code from /Users/sassembla/Desktop/forge-tools/sample/src

[   INFO] writing new app to /Users/sassembla/Desktop/forge-tools/sample/development

[   INFO] Checking JavaScript files...

[   INFO] JavaScript check complete

[   INFO] Verifying your configuration settings...

[   INFO] Configuration settings check complete

[   INFO] Starting package process for iOS

[   INFO] going to package: /Users/sassembla/Desktop/forge-tools/sample/development/ios/device-io.trigger.forgef81472a869ef11e19a1b12313d1adcbe.app

[  ERROR] [Errno 2] No such file or directory: u'' while running package_ios((), {})

[  ERROR] Something went wrong that we didn't expect:

[  ERROR] [Errno 2] No such file or directory: u''

[  ERROR] See /Users/sassembla/Desktop/forge-tools/sample/forge-error.log for more details

[  ERROR] Please contact support@trigger.io


以上。

俺の旅は終わった。

wrote 12/03/05 9:57:07

GWT with お前ら



概要

GWTがどんな感じか数時間で理解して離れる

DartいいよDart! 流行らないと思ってるけどな!



GWTいいところ

Javaで書ける

JavaScriptも書ける(頑張ればその部分はCoffeeで書くとかも出来ると思う。)



GWT厭なところ

Javaじゃない

結局JavaScriptになる


参考

http://dl.dropbox.com/u/7807380/11%3A06%3A15%2015-22-54.pdf


導入

Eclipseにプラグインいれる

http://dl.google.com/eclipse/plugin/3.7


GWTとか入れればおk



リポジトリ

git@github.com:sassembla/SampleGWTProject-For-Test-installetion-.git



書いて動かす

適当にやる。


テストモードって言ってねー、てへっ

初回起動めっちゃおそいのー。

でもそこからは部分更新とかホットリロード効くのー。


テスト

JUnitでのテストが可能。 要 extend GWTTestCase


☆コンパイルされる対象はsrc/package/client 以下なので、

test/package/client の下にテスト置かないとそもコンパイルされない!


com.google.gwt.junit.JUnitFatalLaunchException: The test class 'com.kissaki.SampleGWT2Tests' was not found in module 'com.kissaki.gwtsampleproject'; no compilation unit for that type was seen


とか言われる。


☆GAE + GWTで構成を作ると、GAEのLibパスのほうが先に評価(リンク)される。

これが問題を生む。GWTのJUnit実装が解決される前にGAE側で解決されちゃう。

解決順 = Order なので、 BuildPath > Order and Export で、

GWTのライブラリをGAEのライブラリより上に持って来る。

で完了。



・JUnitとして実行

JUnitのクラス書いて、アノテーション書いて、実行。

・GWTTestとして実行

module名をnullから正式なもの

(package名+アプリ名)

にすると、GWTTestが走る。

パスを間違えたりすると、走らない。エラーは出る。



実際のブラウザでテスト

テストもブラウザで走らせられる。

-d32 -Dgwt.args="-runStyle Manual:0"

をVMArgumentにつけて実行。


wrote 12/03/05 16:22:47

Gradleを使ってみる


概要

Gradleを使って最低限のビルドとテストを行う

Github

https://github.com/gradle/gradle


公式サイト

http://gradle.org/


たまたまタイミングだと思うけど、自分がDLできなかった(サーバエラーっぽい

ので、

GithubからのDL > Buildと行った。


構成

Cloneして、そっからスタート。


ソースからコンパイル

./gradlew build


インストール

./gradlew install -Pgradle_installPath=/usr/local/gradle-source-build




パスとか弄らないままversion

./usr/local/gradle-source-build/bin/gradle -version


1.0 milestone…とか出るはず。



Screencast

インストール後の使い方の様子をプロジェクト作成からテスト走らせるまで。

http://www.screenr.com/ih88


使い方

(Screencastとは名前が異なります)

Eclipseで適当にプロジェクト一つ作ります

src/some/package/SampleProject


一つクラス追加

HelloWorld.java


JUnitを使ったテストクラスを追加

SampleTests.java


test/some/package/SampleTests.java の形で置く


srcフォルダと同じ階層に build.gradle ファイル追加



内容を記述

apply plugin:'java'



//add dependenncies into this build-rule

dependencies {

testCompile 'junit:junit:4.8.2'

}



//set repositories for this build-rule

repositories {

mavenCentral();

}



//change test-source dir from src/test/java to below

sourceSets {

  test {

    java {

      srcDir "test/com/kissaki"

    }

  }

}


このあと、

該当するbuild.gradle のあるフォルダまで行ってから、

gradle build とするとビルド、

gradle test とするとテストが走ります。


Screencastだと、いきなりテストを行い、テスト側に

fail(not yet implemented);

があるので、失敗してます。


testを実行するとき、 -i オプションを付ける事で、詳細を表示していますが、

レポート自体は

srcと同じ階層に

build

フォルダが勝手に生成され、

build/reports/tests/ 

に、index.htmlと、パッケージ名.html という形でテスト結果が出力されてます。


build.gradle内容解説

・apply plugin:'java' で、javaだよーって宣言してます。

これによって、gradleが見るsrcとかtestとかのパスのルールが決定されています。


・dependencies には、依存している(以下略)


・テストのソースの場所設定を、sourceSetsで行ってます。

デフォルトの位置は、javaの場合、

src/test/java/ 下になります。

ちなみにこの設定でtestフォルダの位置を変えてるのは、

たまたま近所にあったGWTの構成がそうだったから。

必然性はありません。



GradleのTextMateBundleがあった

https://github.com/gradle/gradle.tmbundle




ご意見ご感想は @toru_inoue まで。あるもんならな!!

wrote 12/03/04 19:17:13

AndroidでScala


(より具体的には)

コレ

http://www.zusaar.com/event/203004


なるせくんにようこそ&頼むぜー報酬を渡して


IntelliJでScalaの構文サポートできる状態になったうえで、 Androidのコードを書いて

ビルドはコマンドラインで行って

テストは通らなかった会

こんご、なるせ君が「世界のなるせ」にレベルアップして

歴史改変してくれるらしい。



死霊

ずさー見ろ。


要DL的な意味で必要なもの

全部死霊に書いてあるけど上げると


IntelliJ


Scala

sbt

conscript

giter8


Android SDK

メモ

IntelliJの設定で、Scalaのビルドパスやらで詰った。

設定するタイミングがEclipseと違うだけ。

Eclipse脳怖い。


IntelliJでAndroid-Scalaを書いているとき、Scalaが適宜ビルドされない(当たり前)ので

構文的には合ってるんだけどコンパイル的には通らないアバババな状態になり困った

Eclipse脳怖い。


Android-Scalaというg8に登録されているセットを使ってやってみたが、

proguardのオン/オフでビルド後実実行が出来なくて全米が泣いた。


結論

ScalaとかIntelliJ、Android単体はOK。


AndroidとIntelliJの変態タッグが怖い。

トリオになるともっと怖い。


この組み合わせについて、

全参加者の膝に矢が刺さったと思う。


最後に

なるせくんありがとうありがとう!

タメになったッ!

wrote 12/03/03 12:26:12

iRails


うわごとver.(世界の何処かにはきっともうステキな奴があると思うの)

あとどこまで想像できますかねって感じの話。


概要

RubyOnRailsのような形で作れるiOSのアプリケーションフレームワーク自動生成を目指す。

View、API、テストについて、毎回書いているものを自動的に作れるような機構を目指す。


参考にするのは、Scaffold。

iRails scaffold "something"


M系

何か用意するのは大賛成。


V系

VCとセット。単独は無い。

VC系

特に簡単に生成できそうなもの。UIDesignとの接続子をどう捏造するかがキモ


C系

純粋なCは、単独の処理を行うものとして書く。



目的(Motivation)

Webサービスで良くあるインターフェースプレイヤー(InterfacePlayer)を、

Scaffoldで作れるようにする。

ようはTitaniumをWebサービス特化させたものをクライアント(iOS)側から作る。

→スモールスタート、開始時に必要十分な実装と対策、改変の余地

Titaniumの導入簡単さ+Rails


手段(Proposal)

MessengerSystemでの疎結合を自動生成する。

っていうかほとんどメモリ管理無しで行けるはず。


箱(View)と構造(Controller/Routing)と遠い記録機構(Client-Server-ORM)を自動生成する。

Routingが拡張され、遷移になる。(書くとこ違ったのでうつした obhr)

遷移を宣言的に行えると凄く嬉しい。

→MessengerにReactorを付ける、PluggableMessengerとか(obhr)


課題

想像できる成果物が、

サーバサイド(Rails)+クライアントサイド(Titanium)

の、iOSアプリ側からのScaffold。


で、これって初期目的に合ってる?(obhr)

正直、作った所で自分たち以外は使わなそう。(tino)

→なので、iOS側は今後もありそうなので本気で、

Web側はRoRが叩ければそれで良いと思う。

wrote 12/02/26 18:08:29

ViewAPIについて


概要

現在のブラウザ/クライアントサイドで行える、ビューを作る、という行為を、

簡単なAPIに纏める。

たとえば、下記の形で、どこからかトリガーが引ければOK、という形にしたい。


*記法は、まだ特定の言語を規定するものではない。


ViewController.show().dialog()

ダイアログを作成

globalDialog.setStyle(http:style/classic)

ダイアログの表現処理をロードする

→Viewが表示される


全てのViewの動作の根源は、それが表示される事。

なので、

そこを基礎として、クライアント上にViewが適当に構築される事を望む。

addされたら表示、overlayされたら表示、とか、判りやすい感じに出来るはず。

UIのControlも基本面積に依存する。


モチベーション だれの為のものなのか

Viewを作る際の現在のソリューションとしては、

js、css、Flash、image、movie、htmlなど、多種の要素がある。

これを、いちいち選び組み合わせるのが面倒くさい。


こう感じる俺/あるいは誰か のための、HTMLとその近辺にある描画技術から

Viewを切り離す為の試み。



理想

デザイン作業とHTML/他のリソース構築を切り離す


wrote 12/01/29 18:37:00

GitRepositoryDropbox内に作成



概要

GitRepositoryDropbox内に作成する。

出来ると、まあ、ウマーって感じで。



手法

なんの事は無い、Dropboxの設定で、

マシン内にDropboxフォルダを作った後で、

通常のgitの所作を行うのみ。



操作

Dropbox内で、


mkdir origin.git

cd origin.git

git init --bare



コミットとか

他所のRepoで、

git remote add origin (Dropbox/とかマシン内のアドレス)origin.git

git commit -m "なにかしら" 変更を加えたファイル

git push origin master


以上

wrote 12/01/10 12:11:20

yuroyoroさんの死霊にみちびかれるままsbtを入れてみたりする話



そもsbtってなんなのさ

判ってない。

→SimpleBuildToolの略。

で。

・最新版は一個前のstableを使ってビルドする

という事なので、導入するには一個前のビルドツールを落としてきて、

それを使って最新の環境をビルドする事になる。


最終的に出来上がるものは、

Scalaのプログラムをビルドする為のjarファイル


ビルドに使うツールとしての、直前のバージョンのsbtをDL

sbt-launch.jar



ビルドする対象一式をDL

git clone git://github.com/harrah/xsbt.git


ビルド用のsbtを使って、最新のsbtをコンパイルする。

、、、

んだけど、ぶっちゃけこの作業の必要性ってあんま無い。


どうしてもって言うなら止めないけど、macportsとかで最新のsbtが苦もなく手に入ったりするし。

うん。


どうしてもっていうなら、

sbt build-all とかでビルドが開始される。だけどまだやるなよ、



build-allは大体の場合、メモリエラーが出る。OutOfMemoryError。PermGen space関連。


これは、ただ単に色々デカすぎるものを一発でビルドしようとしている為。

次の2点で対応。

→ビルドに使用するsbt自体の設定を、少し弄ってみた。

-XX:+CMSClassUnloadingEnabled -XX:MaxPermSize=256m

→個別にビルド

publish-local, proguard,sxr,doc4構成なので、個別に

sbt publish-local とかやってあげれば、まだ平和に事が進む。



セットアップと試し

mkdir hello

cd hello

echo 'object Hi { def main(args: Array[String]) = println("Hi!") }' > hw.scala

sbt 

とかやると、初回であればいろんなコンポーネントを取得して来る。

で、

自分はエラーが出た。

[NOT FOUND  ] commons-logging#commons-logging;1.0.4!commons-logging.jar


無い、って言われるのだけれど、調べてみると、

http://blog.teksol.info/tags/scala

依存性解決に失敗してるケースがあるみたい。

実際には.ivy2.m2を削除すると正確に動く。

クリーンインストール前提の罠。


ちなみに問題のivy2とm2は、Jenkinsがらみで先に入ってたものっぽい。

フォルダだけ作ってた系だろうか。

環境再現がとりにくい、、、


取得するものがそれ以上なくなれば、REPLの状態になる。


[info] Set current project to default-cde796 (in build file:/Users/sassembla/test/hello/)

これは、現在のプロジェクトをフォルダ~の場所にセットしましたよって情報。

で、

> run

ビルドして起動する。

[info] Running Hi 

Hi!

[success] Total time: 1 s, completed 2011/12/25 11:03:08



TextMateと連携させてみる

自分はTextMate使いたいので、バンドルを探してみた。

下記に紹介があった。

http://www.sidewayscoding.com/2010/08/using-textmate-for-scala-development.html

バンドルをダウンロードして取得

git clone git://github.com/mads379/scala.tmbundle.git

出来たバンドルファイルを開くと、それだけでTextMateにインストールされる。

スクリーンショット 2011-12-25 11.10.19.png

これで、シンタックスハイライトが効く。

スクリーンショット 2011-12-25 11.11.31.png

この状態でRunさせようとしても、下記のようなエラーが出る。(まあブログの通りなの)

スクリーンショット 2011-12-25 11.12.52.png

SCALA_HOME in TextMate -> Preferences... -> Advanced -> Shell Variables を編集。

ッつー事なので、xsbtだと何処をさせば良いのやら。

wrote 11/12/25 1:54:51

GWTとDartでMessaging

メッセージングとは

  本来の定義とは違いますが、

  ここでは、"オブジェクト間の参照渡しなしで、相互に呼び合うことができる機構"として使っています。

  なにそれ凄い!! って思った方、居たら嬉しいです。

  言語的には、

     関数型言語、一部のオブジェクト指向言語で仕様として用意されています。

Scalaとか、
Objective-Cとか。 


GWTでメッセージング

  インストールと

  サンプル実行と

  メッセージングをやってみよう的な。



ダウンロード このへん

https://gitorious.org/messengersystem-gwt#more

DLして→importして、、って、コレからサクッとやってみます。 

ScreenCastにあるので、まあ解説がてら。

git clone git@gitorious.org:messengersystem-gwt/messengersystem-gwt.git

→Eclipseのプロジェクトなので、Eclipseにimport


実行
各インスタンスからWindow.alertがでますた。 インスタンスは保持してますが、メソッドは実行していない点に注目。

GWTMessengerでのメッセージング JSのWindow.postMessageを使い、インスタンス間のポインタ手動ではない構造を作ってます。

//何かしらオブジェクトを作ります

Foo foo = new Foo("A");

Foo foo2 = new Foo("B");

>> 

//オブジェクトの中に、メッセージの受け手兼送り手のMessngerGWTImplementsを書いときます。 

messenger = new MessengerGWTImplement(name, this);

//メッセージを送り合う関係を形成するように、(既にここからメッセージングで)親居ますか?ってメッセージを 

環境に投げます。この場合は、myselfって名前の人を親として設定します。

messenger.sInputParent("myself"); 

<<

//親設定のオブジェクトmyself から、Aにメッセージを送る messenger.call("A", "fooCommand",

messenger.tagValue("fooString", "fooValue"), messenger.tagValue("fooNumber", 100.0), messenger.tagValue("fooObject", fooObject)

);


!とどいた!!

みたいな。


Dartでメッセージング

インストールと

サンプル実行と

メッセージングをやってみよう的な。

インストール 簡単Ver

http://www.dartlang.org/docs/getting-started/editor/index-macos.html

めんどいVer(Before Oct 2011) 割愛


インストールして、"Something"ってプロジェクトを作ってみた。

page2image1072.png

プロジェクトを制作すると、 /Users/sassembla/dart 直下にフォルダが出来る。

page2image2056.png

サンプルでいい感じなのはコレ DLしたフォルダの中に、すでにサンプルが一式入ってます。 dart/samples

page3image504.png

Editorから、 File > Open > /dart/samples/sunflower/sunflower.dart dartでは、

.dartパッケージでアプリケーションの管理ファイルを構成している。 開いて実行するとこんな感じ

page3image1792.png

フィボナッチ級数的な感じで、ひまわりが書ける、とか。


本題、メッセージング
頑張って書いた、、んですが、 今朝見たらsampleにisolateってのがあってさ、、

/isolate
作成日:2011/11/9 by Google

page4image504.jpg

なんやてぇぇぇ

俺のミッション、終了のお知らせ。

/dart/samples/isolate

page4image1744.png

実行すると

page5image488.png

中身の解説 

ready()メソッドで、要素を設定してる。

//A,Bのisolate(独立スレッドを持つオブジェクト!)を作る createIsolate("A");
createIsolate("B");

createIsolateメソッドの中で、spawn()メソッドを使っています。

spawnとは、、、!!! 

Future<SendPort> spawn() {

return IsolateNatives.spawn(this, _isLight); 

}


Future型を返す、dart仕様で定義されている(=Runtimeがある)メソッドで、 isolate(独立したオブジェクト = スレッド)を実装します。

spawn()メソッドの特徴として、 ・実行するとコピーが作成され、コピーがスレッド化する

(実装見てませんが、たぶんまんまWebWorker作ってます) で、


//送る

ports[isolateName].call(message).receive( (var message, SendPort replyTo) { 

replyElement.text = message;

});


おしまい

wrote 11/11/13 8:58:41

GroovyについてLion+Macports2.0+Groovy1.8.1でやってみた


概要

SVGの値変更の処理を自動で解析したりして行いたかったので、使ってみた。



インストール

MacPortsをインストール後、

sudo port install groovy


1.8.0の時は呪われていたらしいが、今11/08/22 16:12:24は平気。



使用感

特定のtagを無くす

doc.remove(doc.description)


特定のタグ全ての特定のattrを変更

doc.g.path.each {

    it.@id = "shape" + (i++)

}


超素敵。

アクセッサが天衣無縫で嬉しい。

wrote 11/09/02 13:40:08

GCC/LLVMでコンパイルしたものの中身を見る


概要

ビルド済みのアプリケーションとかの中を見る。


中で何つかってるか判らないライブラリとか、何使って実現してるのかとか

そういったヒントが欲しいときに。



探した結果

http://www.codethecode.com/projects/class-dump/

この辺が使える。



実行

class-dump 知りたいアプリとかのLinux実行コマンド 


でOK。


こんな感じに表示される。

スクリーンショット 2012-04-22 21.29.01.png

スクリーンショット 2012-04-22 21.29.14.png

スクリーンショット 2012-04-22 21.29.21.png

wrote 11/08/24 12:13:34

GWTについて


概要

GWTとは。

GoogleWebToolkit GWT (グウィット 2009年ころにIOで突如言い出してた気がする。)

Googleが作ったJava言語を利用したJSコンパイル技術。FWではない。Java to JSの変換技術。

JSCompiler

・Javaで記述、コンパイル結果がJavaScript(JS)として実装、実働

・Javaのメソッドやクラスが使える

・Eclipseなどと連携可能

ステップ実行ができる、プラグインが使える、などなど鬼便利というかこれが肝コレだけコレが全て

・JUnitが使える、テストが可能

・JavaScript単体では書けないような範囲の物事を、Javaの型安全な世界で記述する事ができる

・JSのローディングやテストを、Javaに関連する世界で自動化できる

・あらかじめ用意されているライブラリがたくさん

イベントリスナ、JSON、JSONP、GUI Widget(ダサい。ダサい。あとダサい。Apple並みとは言わないまでも、、)、

Canvas、Sound、他

・JSも使える Java中JS、JS中Javaが可能

JSNI(JavaScriptNativeInterface)



落とし穴もがっちりある

JavaかとおもったらJSだった。何を言っているかわからねーと思うが(ry

・変換不可能なクラスもある

日付に関するクラスとかが無い。めんどかったんだと思うが。

・Widgetが破滅的にダサい

グラフィカルな面で本当に残念です。ありがとうございます。


・ロードとstaticの関係

staticなどを使うと、優先的にLoadingが組まれる。結果として、名前空間が効かないポイントが生まれたりする。

Javaであればリフレクションなどの手段で明確にアクセスできるところ、偶然名前が一致して衝突、などがあり得る。


・イベントの解除などはJSの癖を引きずる

イベントへのアイデンティファイに対して、制約が多い。根源がJSのリスナなのでしょうがない。

具体的には、特定のオブジェクトのみリスナから外す、という事ができない。

オブジェクトが帰属するクラス単位でのリスナがごっそりと消える。

(リスなのアイデンティファイに着いて、それ以上小さな単位でのアイデンティファイができない)


・JSNIはJSなので何が起こってもおかしく無いし補完が効かない

オハコンの中のオワコン



ところでJavaScriptとはなんだったのか

GWTのようなJSCompilerが生まれた経緯を推察してみる。

JSとは、

HashMap a ... b

b ( =a)

a ( =b)

a(function b()) など。

何でも連鎖マップに入れられ、発火させられる言語

→他の言語でやっている様々な事が、ほぼ、JSでもって、JSを使って、JSの上で実装可能。

ここに闇がある

☆他の言語でやっている様々な事が、ほぼ、JSでもって、JSを使って、JSの上で実装可能。

→言語の中に、同じ言語を使って、機能や仕組みを実装する、という行為には、元来無理がある


だって元々その言語に無いのだもの。

・内部にむき出しの実装が増える事によって、トラブルが増える

「実装した機能」それ自体の実装に触る事ができてしまう

e.g. C++のスマートポインタ、Javaのメッセージング

JavaScriptの場合は、元来無いものが非常に多い。

名前空間(致命傷)、クラス、メッセージング、自己環境把握概念


・実装機能と自分が書き足したものとの区別がつくのは今この瞬間の書いている自分だけ

a = a+b;

a = a+b+c;

1D後、1W後、1Y後に見て、何処が「足された部分」かわかりますか? ッつー話。


・トラブルを起こさないように実装するには、階層を分けてのFW化(e.g. RoR)、ルール化が有用だが、。

フォルダなどによる階層化が不可能→JSには「ブラウザに直接読み込まれる」という制約がある。これは致命傷。

ルールが増える事(ルール爆発)は自殺行為→多彩なルールを守る事にコストがかかってしまう。しかもそれは永遠に続く



→解決策として、コンパイル という「改変」行程が選ばれる。

JSをコンパイルの結果として作りあげる技術たち JSCompiler

Google Closure (JS to JS コンパイル)

強くルール付けされた構造を模倣する事でのプラグイン化

自己制約をパッケージ化する


CoffeeScript (Coffee to JS コンパイル)

JSの穴をあらかじめ殺した記法での記述と、コンパイル処理による最適化、ネームスペースの補助

RoR3系で色々動きがあるらしいが?よく知らない。これからJSをどうしても書かなければ行けない分野では来ると思う。


GWT (Java to JavaScript コンパイル)

Googleが用意した特定のクラス、メソッドがJSに変換される。

コンパイル処理による最適化、パッケージによるネームスペース明示、

staticによるシングルトン明示などができる。

おまけでブラウザ間の差異を勝手に吸収する。

Java言語自体に素敵さが足りないので、後述のJSCompilerたちの方が先があると思う。


Pyjamas (Python to JS コンパイル)

触った事無いからわからん


ClojureScript (Clojure to JS コンパイル)

さわり中 まだよくわからん


ScalaJS (Scala to JS コンパイル ? 未登場)

まだ無いのでわからん 本命。



A to JavaScript の利点

とあるA言語の能力 >>>>>> JSの能力 である前提がある。

Aという言語があり、ルール的にJavaScriptよりも厳格 かつ、機能が定義されているとする。

名前空間、記法制限、型、演算子、メッセージング、クラス、構造体、列挙子、、、


これらを、その言語で書き、JSにコンパイルする。


元々のAという言語にある機能を、Aという言語の記法で使う範囲でのみ担保すればいい。

→最終的に出力されるJSには、手を触れる事が無い(あるとしたらA to JSコンパイラのバグとか不備)

例えばクラスをJSで実装する場合、

JSで直に実装→JSを書く際に、その自己定義した構造にあわせたreadとwriteが必要になる

→ルールを言語の内側につくるので、さらに内側に書くしかない。


他言語で書く場合

→ルールは記述時言語側が持っているため、書き手は意識しないでいい。

→コンパイルされた結果は、ルールが構築されたJSの中に、手続きが記述された状態になる。

→結果は同じであっても、人が煩わされる行程が減っている、自動化できている事に注目。


今の俺の結論

JSオワコン。JSCompilerオハコン。

言語の中に言語で機能を追加する副作用を回避できる。

ブラウザで動く言語がJSに限られている事が一因だが、今後は異なるといいなーとか。JSのライブラリ化とか進むといいなー。



wrote 11/08/16 22:55:34

Macで簡単に日付フォーマットを乱造


概要

こんなのが簡単に作れる。

12/04/22 20:46:11



用途

メモとかしたい時、タイトル考えずにとりあえずでファイルの名前つけるのに役立つ。

秒までみてるので人間がボタン押してる以上は絶対被らない。



AppStoreからインストールする場合

できるようになってた。以下のインストールやんなくていいので楽。

https://itunes.apple.com/jp/app/wordservice/id899972312?mt=12



DL

下記からDL。

http://www.devontechnologies.com/download/products.html

WordService.png


WordService

↑これ。


手順

WordService.service を

HD > Library > Services folder

に放り込む。

もし Services folder フォルダ自体が無ければ、作る。


有効化のため、ログインし直す。



設定

システム環境設定 > キーボード > キーボードショートカット > サービス 

スクリーンショット 2012-04-22 20.50.00.png

スクリーンショット 2012-04-22 20.50.12.png

次のような機能があるはず。

スクリーンショット 2012-04-22 20.50.48.png

スクリーンショット 2012-04-22 20.50.58.png


for example

⌘+_ = 11/07/18 19:00:10



wrote 11/07/18 19:14:32
twitback with Twitter-account